Não, não há como uma string no bash conter um NUL ( c
).
Portanto, uma variável (pois contém uma string) não pôde conter um NUL.
A razão é que o bash é escrito com o paradigma $1
de "uma string termina em um NUL". [1] O kernel do Linux também impõe essa limitação. [2] Mas mesmo que o kernel permitisse NULs em strings [3] (argumentos), a maioria dos shells e bash em particular, não poderiam incluir NULs dentro de variáveis [4] .
Parâmetros posicionais ( $2
, |
, etc.) são equivalentes a variáveis e também não podem conter NULs.
No entanto, nuls pode existir em arquivos, em streams e em printf:
$ printf 'test$ echo $(printf 'test$ zsh -c ' echo $(printf "test$ printf 'test$ myProgram "$parameter1" "$(xxd -ps -c 512 binaryFile.dd)"
nuls$ zsh -c 'a=$(printf "included$ zsh -c 'a=$(printf "included$ bash -c 'a=$(printf "included$ printf 'included$ zsh -c 'printf "included$ printf 'test$ echo $(printf 'test$ zsh -c ' echo $(printf "test$ printf 'test$ myProgram "$parameter1" "$(xxd -ps -c 512 binaryFile.dd)"
nuls$ zsh -c 'a=$(printf "included$ zsh -c 'a=$(printf "included$ bash -c 'a=$(printf "included$ printf 'included$ zsh -c 'printf "included%pre%null" | ( read a; printf "%s\n" "$a" | od -vAn -tx1c )'
69 6e 63 6c 75 64 65 64 00 6e 75 6c 6c 0a
i n c l u d e d %pre% n u l l \n
null' | od -vAn -tx1c
69 6e 63 6c 75 64 65 64 00 6e 75 6c 6c
i n c l u d e d %pre% n u l l
$ printf 'included%pre%null' | ( read a; printf '%s\n' "$a" | od -vAn -tx1c )
69 6e 63 6c 75 64 65 64 6e 75 6c 6c
i n c l u d e d n u l l
null"); /usr/bin/printf "$a"' | od -vAn -tx1c
bash: warning: command substitution: ignored null byte in input
69 6e 63 6c 75 64 65 64 6e 75 6c 6c
i n c l u d e d n u l l
null"); /usr/bin/printf "$a"' | od -vAn -tx1c
69 6e 63 6c 75 64 65 64
i n c l u d e d
null"); printf "$a"' | od -vAn -tx1c
69 6e 63 6c 75 64 65 64 00 6e 75 6c 6c
i n c l u d e d %pre% n u l l
in%pre%files%pre%\n' > testnul.bin
$ cat testnul.bin | xxd -ps
74657374006e756c7300696e0066696c6573000a
$ head -c 7 testnul.bin | xxd -ps
74657374006e75
$ dd if=testnul.bin bs=7 count=1 | xxd -ps
74657374006e75
1+0 records in
1+0 records out
7 bytes copied, 0.000655689 s, 10.7 kB/s
$ dd if=testnul.bin bs=7 count=1 2>/dev/null| xxd -ps
74657374006e75
nuls\n") | od -vAn -tx1c'
74 65 73 74 20 6e 75 6c 73 0a
t e s t n u l s \n
nuls\n') | od -vAn -tx1c
bash: warning: command substitution: ignored null byte in input
74 65 73 74 6e 75 6c 73 0a
t e s t n u l s \n
nuls\n' | od -vAn -tx1c
74 65 73 74 00 6e 75 6c 73 0a
t e s t %pre% n u l s \n
null" | ( read a; printf "%s\n" "$a" | od -vAn -tx1c )'
69 6e 63 6c 75 64 65 64 00 6e 75 6c 6c 0a
i n c l u d e d %pre% n u l l \n
null' | od -vAn -tx1c
69 6e 63 6c 75 64 65 64 00 6e 75 6c 6c
i n c l u d e d %pre% n u l l
$ printf 'included%pre%null' | ( read a; printf '%s\n' "$a" | od -vAn -tx1c )
69 6e 63 6c 75 64 65 64 6e 75 6c 6c
i n c l u d e d n u l l
null"); /usr/bin/printf "$a"' | od -vAn -tx1c
bash: warning: command substitution: ignored null byte in input
69 6e 63 6c 75 64 65 64 6e 75 6c 6c
i n c l u d e d n u l l
null"); /usr/bin/printf "$a"' | od -vAn -tx1c
69 6e 63 6c 75 64 65 64
i n c l u d e d
null"); printf "$a"' | od -vAn -tx1c
69 6e 63 6c 75 64 65 64 00 6e 75 6c 6c
i n c l u d e d %pre% n u l l
in%pre%files%pre%\n' > testnul.bin
$ cat testnul.bin | xxd -ps
74657374006e756c7300696e0066696c6573000a
$ head -c 7 testnul.bin | xxd -ps
74657374006e75
$ dd if=testnul.bin bs=7 count=1 | xxd -ps
74657374006e75
1+0 records in
1+0 records out
7 bytes copied, 0.000655689 s, 10.7 kB/s
$ dd if=testnul.bin bs=7 count=1 2>/dev/null| xxd -ps
74657374006e75
nuls\n") | od -vAn -tx1c'
74 65 73 74 20 6e 75 6c 73 0a
t e s t n u l s \n
nuls\n') | od -vAn -tx1c
bash: warning: command substitution: ignored null byte in input
74 65 73 74 6e 75 6c 73 0a
t e s t n u l s \n
nuls\n' | od -vAn -tx1c
74 65 73 74 00 6e 75 6c 73 0a
t e s t %pre% n u l s \n
Como você pode ver, o printf cria um NUL e flui pelo pipe ( cat
).
Mas as NULs são separadas das "execuções de comandos":
%pre%
No bash 4.4, ele emite um aviso. zsh neste caso, substitua silenciosamente os NULs por um espaço:
%pre%
Podemos criar um arquivo que contenha NULs com printf e head
, tail
, C string
ou dd parte do arquivo que inclui os NULs:
%pre%
No seu caso, não existe uma maneira simples de [5] ter o conteúdo de um arquivo binário como argumento. Talvez a representação hex possa funcionar:
%pre%
Obrigado a @Gilles por todo o trabalho adicional (e detalhes) abaixo.
1
[1]
Tudo se resume à antiga definição de C
que "strings terminam em um NUL ( strcpy
)».
Este paradigma foi codificado em várias bibliotecas e ferramentas execve()
, das quais POSIX tem vários exemplos. Como execve()
aqui que estados (ênfase minha):
The strcpy() function shall copy the string pointed to by s2 (including the terminating NUL character) into the array pointed to by s1.
Isso significa que é assumido que uma cadeia é terminada por um NUL.
Ou, em outras palavras, pode haver apenas um NUL, o último.
2
[2] A chamada do sistema $'%code%'
, também definida no POSIX , espera que as strings (argumentos de comando) terminem em um NUL. É por isso que mesmo shells podem funcionar com NULs (a maioria não, com a notável exceção do zsh):
%pre%
Pode não usar NULs em argumentos passados pela chamada %code% :
%pre%
3
[3] Mas mesmo que o kernel seja capaz de incluir NULs em argumentos, o bash não permitirá:
%pre%
No bash 4.4, ele emite um aviso quando um NUL é removido.
4
[4]
A maioria das shells, e bash em particular, não poderiam incluir NULs dentro de variáveis.
%pre%
Se o shell em execução for zsh, isso (em vez disso) funcionará com um nulo:
%pre%
5
[5]
Significa que uma inclusão "direta" (simples) de um byte de valor 0 ( %code% ) é impossível. Mas um codificado (complexo), seja usando C-string %code% , em hexadecimal, base 64 ou algum equivalente, o valor de zero poderia ser incluído.