O Bash usa sequências de estilo C internamente, que são terminadas por bytes nulos. Isso significa que uma string de Bash (como o valor de uma variável ou um argumento para um comando) nunca pode realmente conter um byte nulo. Por exemplo, este mini-script:
foobar=$'foofor file in * ; do printf '%sprintf '%sfoobar=$'foofor file in * ; do printf '%sprintf '%s%pre%' * \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
' "$file" ; done \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
bar' # foobar='foo' + null byte + 'bar'
echo "${#foobar}" # print length of $foobar
' * \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
' "$file" ; done \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
bar' # foobar='foo' + null byte + 'bar'
echo "${#foobar}" # print length of $foobar
na verdade imprime 3
, porque $foobar
é na verdade apenas 'foo'
: o bar
vem depois do final da string.
Da mesma forma, echo $'foo
apenas imprime foo
bar'echo
, porque
não sabe sobre a parte
bar$'...'
read
.
Como você pode ver, a seqüência -d $'
é realmente muito enganadora em uma string -d ''
'read
-style; parece um byte nulo dentro da string, mas não funciona dessa maneira. No seu primeiro exemplo, o comando ''
tem -d delim
. Isso funciona, mas só porque find
também funciona! (Esse não é um recurso explicitamente documentado de $'
, mas suponho que funcione pelo mesmo motivo: echo "$file"$'
'echo
'printf
é a string vazia, então seu byte de terminação nulo vem imediatamente. $'...'
é documentado como usando "O primeiro caractere de delimitar ", e acho que funciona mesmo se o" primeiro caractere "tiver passado do final da string!
Mas como você sabe do seu exemplo echo
, é possível que um comando imprima um byte nulo, e que o byte seja canalizado para outro comando que o lê como entrada. Nenhuma parte disso depende do armazenamento de um byte nulo em uma string dentro do Bash . O único problema com seu segundo exemplo é que não podemos usar -e
em um argumento para um comando;
poderia felizmente imprimir o byte nulo no final, se soubesse que você queria. printf
Portanto, em vez de usar echo
, você pode usar command echo
, que suporta os mesmos tipos de seqüências de escape que as sequências com echo
. Dessa forma, você pode imprimir um byte nulo sem ter que ter um byte nulo dentro de uma string. Isso ficaria assim:
ou simplesmente isso:
%pre% (Nota: echo
na verdade também tem um $PATH
sinalizador que permitiria processar %code% e imprimir um byte nulo; mas também tentaria processar qualquer sequência especial em seu nome de arquivo. Portanto, o %code% abordagem é mais robusta.)
Aliás, existem alguns shells que fazem permitem bytes nulos dentro de strings. Seu exemplo funciona bem no Zsh, por exemplo (assumindo configurações padrão). No entanto, independentemente do seu shell, sistemas operacionais Unix-like não fornecem uma maneira de incluir bytes nulos dentro de argumentos para programas (já que os argumentos do programa são passados como strings no estilo C), então sempre haverá algumas limitações. (Seu exemplo pode funcionar no Zsh somente porque %code% é um shell embutido, então o Zsh pode invocá-lo sem depender do suporte do sistema operacional para chamar outros programas. Se você usou %code% em vez de %code% , ele ignorou o embutido e usado o programa %code% autônomo no %code% , você veria o mesmo comportamento no Zsh como no Bash.