printf in shell script can't do \x%x
\
is used several times in there:
- for the
`...`
form of command substitution. Best is to use$(...)
. - to escape characters like
$
,`
and\
inside double quotes. Best to use single quotes instead. - to escape
\
in the format argument ofprintf
- to introduce that
\xHH
sequence in the format argument of the otherprintf
(not standard though).
So it should either be:
printf `printf "\\\\\\\\x%x" 255 255 255 0`
printf `printf '\\\\x%x' 255 255 255 0`
printf $(printf '\\x%x' 255 255 255 0)
That is, you need to pass \\
to the rightmost printf
for it to output \
, but with `...`
, you'd need to escape each \
with \
, and do that again for "..."
.
That's still invoking the split+glob operator which we don't want here. So:
printf "$(printf '\\x%x' 255 255 255 0)"
Or portably:
printf "$(printf '\\%o' 255 255 255 0)"
With some awk
implementations (not all with work with 0):
LC_ALL=C awk 'BEGIN{printf "%c%c%c%c", 255, 255, 255, 0}'
With perl
:
perl -e 'print pack "C*", @ARGV' 255 255 255 0
zsh
alternative that avoids forking a subshell:
(){setopt localoptions nomultibyte; printf %s ${(#)@}} 255 255 255 0
bash
alternative that avoids forking a subshell (also works in recent versions of zsh
):
printf -v x '\\%o' 255 255 255 0
printf "$x"
Related videos on Youtube
Paul Wratt
Updated on September 18, 2022Comments
-
Paul Wratt over 1 year
where
ECHO-VAR
produces\xFF\xFF\xFF\x00
($fb_COLOR15
) these work on the command line:CP="`ECHO-VAR`" printf $CP | dd status=none bs=4 count=$(( ( 1360 * 100 ) + 100 )) > /dev/fb0 printf "`ECHO-VAR`" | dd status=none bs=4 count=$(( ( 1360 * 100 ) + 100 )) > /dev/fb0 printf "${fb_COLOR15}" | dd status=none bs=4 count=$(( ( 1360 * 100 ) + 100 )) > /dev/fb0
but they don't work in a shell script (
#!/bin/sh
). It will only output\xFF\xFF\xFF\x00
orxFFxFFxFFx00
instead of four (4) characters, even if piped throughsed 's/\\/\\\\\\\\\\/g'
.these work but with
bash: printf: missing hex digit for \x
(x4), they produce what you expect at the end:printf `printf "\x%x\x%x\x%x\x%x" 255 255 255 0` | dd status=none bs=4 count=$(( ( 1360 * 100 ) + 100 )) > /dev/fb0 printf "`printf "\\x%x\\x%x\\x%x\\x%x" 255 255 255 0`" | dd status=none bs=4 count=$(( ( 1360 * 100 ) + 100 )) > /dev/fb0 printf "`printf "\\\x%x\\\x%x\\\x%x\\\x%x" 255 255 255 0`" | dd status=none bs=4 count=$(( ( 1360 * 100 ) + 100 )) > /dev/fb0 printf "`printf "\\\\x%x\\\\x%x\\\\x%x\\\\x%x" 255 255 255 0`" | dd status=none bs=4 count=$(( ( 1360 * 100 ) + 100 )) > /dev/fb0
however this works (five slashes):
printf "`printf "\\\\\x%x\\\\\x%x\\\\\x%x\\\\\x%x" 255 255 255 0`" | dd status=none bs=4 count=$(( ( 1360 * 100 ) + 100 )) > /dev/fb0
but not in a shell script (
#!/bin/sh
), it produces the same error.I tried various combinations of ` execution, layered echo's and printf's for 5 hours before changing the input format from \x type to the four decimal argument format, which still failed.
FYI: they will produce a white dot on a 32bit framebuffer.
In 5 minutes I got it to work from both the command line and in a shell script using:
bas d2a.bas 255 255 255 0 | dd status=none bs=4 count=$(( ( 1360 * 100 ) + 100 )) > /dev/fb0
d2a.bas
:1 rem D2A.BAS - decimal arguments to ASCII characters 10 for i=1 to 255 20 a$=command$(i) 30 if a$="" then 40 i=255 50 else 60 a=val(A$) 70 print chr$(a); 80 end if 90 next
I understand that the shell process one layer of escaped \ characters for each level of abstraction, and that a command or binary (I also tested
/usr/bin/printf
) parses another layer of escaped \ characters.But I don't understand why I could not get any form of either format to work in a shell script, which should work simply by adding an extra \ character for every one present in an output string.
Does anyone know what is going on, or is this an actual bug?
I believe this is a bug in BASH when in SH mode; see post below, or just save yourself the hassle and use the BAS script.
-
Paul Wratt over 6 yearsI just tested the "portably" (double printf) which worked. So basically I just missed the right combinations (specifically $( \\ and %o )
-
Paul Wratt over 6 yearsI want to keep maximum protability with low overhead, least installed, ie. not AWK and not PERL
-
Paul Wratt over 6 yearswith the \x form, when it should have worked in a script it was getting interfered with producing
xFFxFFxFFx00