0

I'm outputting an echo -ne command to a file in my set-up script for a usb mouse HID.

Here is the script, which is run as root through /etc/rc.local at bootup:

#accidentally had a newline here <---  
#!/bin/bash
cd /sys/kernel/config/usb_gadget/
mkdir -p isticktoit
cd isticktoit
echo 0x1d6b > idVendor # Linux Foundation
echo 0x0104 > idProduct # Multifunction Composite Gadget
echo 0x0100 > bcdDevice # v1.0.0
echo 0x0200 > bcdUSB # USB2
mkdir -p strings/0x409
echo "fedcba9876543210" > strings/0x409/serialnumber
echo "JW" > strings/0x409/manufacturer
echo "DoItForTheWenHua" > strings/0x409/product
mkdir -p configs/c.1/strings/0x409
echo "Config 1" > configs/c.1/strings/0x409/configuration
echo 0x80 > configs/c.1/bmAttributes
echo 250 > configs/c.1/MaxPower
# Add functions here
mkdir -p functions/hid.usb0
echo 1 > functions/hid.usb0/protocol
echo 1 > functions/hid.usb0/subclass
echo 3 > functions/hid.usb0/report_length
# NEXT LINE CAUSES ISSUES 
echo -ne \\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\02\\x81\\x06\\xc0\\xc0 > functions/hid.usb0/report_desc
ln -s functions/hid.usb0 configs/c.1/
# End functions
ls /sys/class/udc > UDC

The expected result of the echo -ne is a sequence of chars being written to file functions/hid.usb0/report_desc starting with 0x05, 0x01, 0x09, etc. Instead I got

$ cat /sys/kernel/config/usb_gadget/isticktoit/functions/hid.usb0/report_desc
-ne \x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03\x15\x00\x25\x01\x95\02\x81\x06\xc0\xc0

When I tried to test this, I couldn't reproduce it. Running the command in bash (works):

pi@raspberrypi:~ $ echo -ne "\\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x03\\x05\\x01\\x09\\x30\\x09\\x31\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x02\\x81\\x06\\xc0\\xc0"
        ▒       ▒       )%▒u▒▒u▒        0       1▒▒▒▒▒

Running a test script (works):

pi@raspberrypi:~ $ cat test
        ▒       ▒       )%▒u▒▒u▒        0       1▒▒▒▒▒
pi@raspberrypi:~ $ cat test.sh
#!/bin/bash

echo -ne "\\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x03\\x05\\x01\\x09\\x30\\x09\\x31\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x02\\x81\\x06\\xc0\\xc0" > test
pi@raspberrypi:~ $ ./test.sh
pi@raspberrypi:~ $ cat test
        ▒       ▒       )%▒u▒▒u▒        0       1▒▒▒▒▒P

Bash redirect (works):

pi@raspberrypi:~ $ echo -ne "\\x05\\x01\\x09\\x02\\xa1\\x01\\x09\\x01\\xa1\\x00\\x05\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x03\\x05\\x01\\x09\\x30\\x09\\x31\\x15\\x81\\x25\\x7f\\x75\\x08\\x95\\x02\\x81\\x06\\xc0\\xc0" > test
pi@raspberrypi:~ $ cat test
        ▒       ▒  )%▒u▒▒u▒        0       1▒▒▒▒▒

So, what did I do wrong here?

Answer: I didn't put the shebang on the right line, it caused another shell to interpret my script.

James Meas
  • 13
  • 5
  • So I "solved" it by just deleting the file and pasting the script back in from here. NOT satisfied with this solution, so the question still stands. – James Meas Jul 10 '18 at 08:44
  • I can reproduce this under very specific conditions. How did/do you call it from /etc/rc.local? (The full and exact command line, please.) – Chris Davies Jul 10 '18 at 19:48
  • I'm still really puzzled, I have two different scripts that look really similar, but they perform different. In rc.local, I used the full path on one line. /opt/scripts/usb_keyboard.sh – James Meas Jul 10 '18 at 19:55
  • I have something interesting to report. When using file on each script, the properly functioning script reports that it is a Bourne-Again shell script, with ASCII text executable, and the other reports only that it is ASCII text. They are both suffixed by .sh extension and have #!/bin/bash shebang. – James Meas Jul 10 '18 at 19:57
  • Ok, I was missing shebang on first line (i accidentally inserted a line break on first line). This was likely the issue here. Now both files report as a BASH script. – James Meas Jul 10 '18 at 20:00
  • Yeah, that was the problem. I updated my post. – James Meas Jul 10 '18 at 20:08

1 Answers1

3

The behaviour of echo is notoriously unportable. Your script probably runs with some other shell when it doesn't work. (You're not running sh scriptname, are you?) See, e.g. how echo differs in Bash and Dash:

$ bash -c 'echo -ne \\x41\\x42\\x43\\x0a'
ABC

$ dash -c 'echo -ne \\x41\\x42\\x43\\x0a'
-ne \x41\x42\x43\x0a

Usually, it's better to use printf instead, but that alone won't help, as not all printfs support hex character escapes (\x00), only octals (\000) so you'd need to change the content too. In any case, in Bash printf \\x41\\x42\\x43\\x0a would do the same as Bash's echo -en \\x41\\x42\\x43\\x0a but slightly more portably.

You'll need to check what shell runs the script.

See also: Why is printf better than echo?

ilkkachu
  • 138,973
  • Very good to know, thanks. I'll look into which shell is running my script (I'm not using sh scriptname, so it should be bash, but like you said it could be run with another shell). – James Meas Jul 10 '18 at 09:32
  • Correct, since bash exists, echo has become a problem. Before, there was an agreement that only two variants exist: UCB and SystemV and that the UCB variant is used in case that /usr/ucb is in front of PATH. Now it seems that even printf is becomming a problem, since there are too many non-conforming implementations, see: https://www.in-ulm.de/~mascheck/various/echo+printf/ The only implementation that follows the POSIX standard with printf is bosh. – schily Jul 10 '18 at 09:43
  • Dash printf differs from bash printf on my machine. Bash printf can do escaped hex but dash printf prints the literal \x00 – James Meas Jul 10 '18 at 19:28
  • In dash $ printf \\x23 \x23 In bash $ printf \\x23 # – James Meas Jul 10 '18 at 20:03