printf no script de shell não pode fazer \ x% x

2

onde ECHO-VAR produz \xFF\xFF\xFF\x00 ( $fb_COLOR15 ) estes trabalham na linha de comando:

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

mas eles não funcionam em um script de shell ( #!/bin/sh ). Ele emitirá apenas \xFF\xFF\xFF\x00 ou xFFxFFxFFx00 em vez de quatro (4) caracteres, mesmo que canalizado através de sed 's/\/\\\\\/g' .

esses trabalhos, mas com bash: printf: missing hex digit for \x (x4), produzem o que você espera no final:

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

no entanto, isso funciona (cinco barras):

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

mas não em um script de shell ( #!/bin/sh ), ele produz o mesmo erro.

Eu tentei várias combinações de 'execução, eco em camadas e printf's por 5 horas antes de alterar o formato de entrada do tipo \ x para o formato de quatro argumentos decimais, que ainda falhava.

FYI: eles produzirão um ponto branco em um framebuffer de 32 bits.

Em 5 minutos, consegui que funcionasse tanto na linha de comando quanto em um shell script usando:

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

Eu entendo que o shell processa uma camada de escapes \ caracteres para cada nível de abstração, e que um comando ou binário (eu também testei /usr/bin/printf ) analisa outra camada de caracteres \ escapados.

Mas não entendo por que não consegui usar qualquer formato para trabalhar em um shell script, o que deve funcionar simplesmente adicionando um caractere \ extra para cada um presente em uma string de saída.

Alguém sabe o que está acontecendo ou isso é um bug real?

Eu acredito que este é um bug no BASH quando no modo SH; veja o post abaixo, ou apenas salve o problema e use o script BAS.

    
por Paul Wratt 14.09.2017 / 16:00

2 respostas

2

\ é usado várias vezes:

  • para a forma '...' de substituição de comando. Melhor é usar $(...) .
  • para escapar de caracteres como $ , ' e \ entre aspas duplas. Melhor usar aspas simples em vez disso.
  • para escapar de \ no argumento de formato de printf
  • para introduzir essa sequência de \xHH no argumento de formato do outro printf (embora não padrão).

Por isso, deve ser:

printf 'printf "\\\\x%x" 255 255 255 0'
printf 'printf '\\x%x' 255 255 255 0'
printf $(printf '\x%x' 255 255 255 0)

Ou seja, você precisa transmitir \ para a direita printf para gerar \ , mas com '...' , você precisará escapar de cada \ com \ e isso novamente por "..." .

Isso ainda está invocando o operador split + glob que não queremos aqui. Então:

printf "$(printf '\x%x' 255 255 255 0)"

Ou portavelmente:

printf "$(printf '\%o' 255 255 255 0)"

Com algumas implementações de awk (nem todas com o trabalho com 0):

LC_ALL=C awk 'BEGIN{printf "%c%c%c%c", 255, 255, 255, 0}'

com perl :

perl -e 'print pack "C*", @ARGV' 255 255 255 0

zsh alternativa que evita o bifurcação de um subshell:

(){setopt localoptions nomultibyte; printf %s ${(#)@}} 255 255 255 0

bash alternativa que evita bifurcar um subshell (também funciona em versões recentes de zsh ):

printf -v x '\%o' 255 255 255 0
printf "$x"
    
por 14.09.2017 / 16:18
0

Acabei de encontrar o mesmo problema novamente e, dessa vez, não consegui refatorar os dados de entrada para torná-lo decimal .

A menos que alguém mais possa mostrar o contrário, o% interno% em BASH quando no modo SH não pode não imprimir caracteres "\ xFF", apesar do que o homem e ajuda páginas dizem. Eu diria que isso é um bug, pelo menos em BASH.

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

Se você remover as aspas da string, a shell as escapará sem processar a printf part.

O que funciona então:

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

Portanto, a solução atual, se você tiver apenas hexadecimal como texto , e quiser um caractere ou byte , canaliza cada byte (texto) para um arquivo de script (como o segundo código demonstra) com x prefixado (antes) de cada valor, \x do script de dentro do seu script e executado o script na próxima linha e remova o script, se necessário.

    
por 27.09.2017 / 06:29