2

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 or xFFxFFxFFx00 instead of four (4) characters, even if piped through sed '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.

2

\ 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 of printf
  • to introduce that \xHH sequence in the format argument of the other printf (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"
  • I just tested the "portably" (double printf) which worked. So basically I just missed the right combinations (specifically $( \\ and %o ) – Paul Wratt Sep 14 '17 at 14:28
  • I want to keep maximum protability with low overhead, least installed, ie. not AWK and not PERL – Paul Wratt Sep 14 '17 at 14:29
  • with the \x form, when it should have worked in a script it was getting interfered with producing xFFxFFxFFx00 – Paul Wratt Sep 14 '17 at 14:44
0

I just ran into the same problem again, and this time I could not refactor the input data to make it decimal.

Unless anyone else can show otherwise, the internal printf in BASH when in SH mode can not print "\xFF" characters, despite what the man and help pages say. I would say this is a bug, in BASH at least.

#!/bin/sh
printf "\x46\x47"

If you remove the quotes from the string, the shell will escape them away without processing the x part.

What does work then:

#!/bin/sh
PF=`which printf`
$PF "\x46\x47"

So the current solution, if you only have hexadecimal as text, and you want a character or byte, pipe each (text) byte out to a script file (as the second code demonstrates) with \x prepended (before) each value, chmod the script from inside you script, then execute the script on the next line, and remove the script if need be.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.