The implementation of printf
in some shells (bash
, ksh
, zsh
, at least; even in sh
emulation mode) understands \xHH
as the hexadecimal number HH
. This is however an extension to the standard printf
specification.
What's required by the POSIX standard is that printf
recognize \0ddd
, where ddd
is a zero, one, two, or three digit octal number.
The shell that stands in for /bin/sh
on your system is most likely dash
(or, less likely, yash
), which understands octal (like all standard shells), but does not understand hexadecimal, when used with printf
.
The hexadecimal number 30 is 60 in octal, so
$ sh -c 'printf "%b\n" "$1"' sh '\060'
0
Or, if you don't want to pass the octal number as an argument but instead want to use it as a static literal:
$ sh -c 'printf "\060\n"'
0
(Note the difference here to the sh -c
statement in your question: the whole printf
statement, including its arguments, are part of the string given as the option-argument to the sh
utility's -c
option. I'm assuming what you have in your question is a simple typo.)
The reason your script managed to print a zero correctly is either because you had a #!
-line in the script that pointed to the bash
shell executable, or you had no such line at all and instead ran the script from an interactive bash
shell. The bash
shell, when executing a shell script with no #!
line, will use bash
to run it (see Which shell interpreter runs a script with no shebang? for more about this detail).
When you run the script with an explicit interpreter, as in sh myScript.sh
, the #!
line, if there is one, will be ignored.
\060
– steeldriver Dec 31 '20 at 22:32sh myScript.sh
, then you have explicitly told sh (i.e. dash) to execute the text of your script itself. The shebang (because it starts with#
) is just a comment in that case. The#!
is a "magic number" which is only actioned when the file containing it is executed via the execve() system call. – Paul_Pedant Dec 31 '20 at 23:24