Ugh! Found it.
Ensure you're not accidentally sending a newline char (\n
) at the end of the command
It looks like echo
adds a trailing newline to the string, whereas printf
does NOT, and this trailing newline character is interfering with the device's ability to parse the command. If I forcefully add it (a newline char, \n
) to the end of the printf
cmd, then it fails too--meaning the device will not respond to the command as expected:
# fails:
printf 'measure:voltage? ch1\n' | timeout 0.2 nc 192.168.0.1 9999
...and it looks like you can suppress the trailing newline from echo
by using -n
:
# works!
echo -n 'measure:voltage? ch1' | timeout 0.2 nc 192.168.0.1 9999
# also works, of course, as stated in the question
printf 'measure:voltage? ch1' | timeout 0.2 nc 192.168.0.1 9999
From man echo
:
-n do not output the trailing newline
Key takeaway: use printf
or echo -n
to NOT have a trailing newline character at the end of your prints.
BUT, that's not the end of it! Here are two more points:
1. Don't use echo
at all in any shell scripts if you want portable and expected behavior, and the ability to send any command to the device!
Using echo
at all is actually a bad idea when trying to use it to send any possible string to the device! Why? Well, @Jeff Schaller pointed out the following resource to me in the comments, and it has tons of really valuable information: Unix & Linux: Why is printf better than echo?.
A few of the key reasons why NOT to use echo
include:
Its implementation, arguments, and behavior are all a bit hacky.
It is not portable: it has various implementations which differ widely across systems. Some support -e
and -n
, some don't. Some have the -e
behaviors by default without -e
. Etc.
It cannot print -n
as a command, at all on some shells. See my comment here.
On bash on Ubuntu 18.04 and 20.04, echo "-n"
should output -n
. Instead, it outputs nothing since it accepts that as the same thing as the -n
flag. echo -- "-n"
should solve that and output -n
, but it doesn't. It outputs -- -n
instead. I see your point very well now. printf
is better.
As @Charles Duffy points out in the comments: even the POSIX specification for echo
recommends not using echo
due to many of these inconsistencies and reasons:
It is not possible to use echo
portably across all POSIX systems...
New applications are encouraged to use printf
instead of echo
.
FYI, here are a couple key quotes from Unix & Linux: Why is printf better than echo?:
Regarding echo
:
...make sure that $var
doesn't contain backslash characters and doesn't start with -
Regarding printf
:
But remember the first argument is the format, so shouldn't contain variable/uncontrolled data.
2. Use printf
properly as printf '%s' "my command string"
, NOT printf "my command string"
See more of the discussion in the comments below, between myself and @Charles Duffy. You should use printf
like this instead:
# CORRECT USAGE: >>> FINAL ANSWER; DO THIS! <<<
printf '%s' 'measure:voltage? ch1' | timeout 0.2 nc 192.168.0.1 9999
# NOT this:
printf 'measure:voltage? ch1' | timeout 0.2 nc 192.168.0.1 9999
This is because the first argument passed to printf
is parsed as the format string. If the command string you're trying to send to the device is %s
, for instance, this doesn't send anything!:
printf "%s"
The output is empty since printf
interprets the first argument as a format string, and %s
means something special in format strings. But this does send the %s
as a literal:
printf "%s" "%s"
The output is
%s
The first "%s"
in the arguments to printf
is the format string, and the second "s"
is the string literal to substitute into the format string where the first %s
lies, according to the printf
specification.
This means that the correct usage of printf
will be able to send ANY command to the device, whereas the incorrect usage will strip out any formatting chars such as %s
, %02X
, %u
, etc etc--any of the printf
-style format string special chars or sequences.
See also:
- Unix & Linux: Why is printf better than echo?
- the POSIX specification for
echo
- My netcat tutorial: ServerFault: General netcat (
nc
) usage instructions, including setting the IP address to bind to when receiving, or to send to when sending
echo
and "So what that means is that you can't use echo to display uncontrolled data"): unix.stackexchange.com/questions/65803/… – Grus