O Bash usa seqüências de caracteres de estilo C internamente, que são terminadas por bytes nulos. Isso significa que uma string 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=$'foo\0bar' # foobar='foo' + null byte + 'bar'
echo "${#foobar}" # print length of $foobar
realmente imprime 3
, porque $foobar
na verdade é apenas 'foo'
: o bar
vem após o final da string.
Da mesma forma, echo $'foo\0bar'
apenas imprime foo
, porque echo
não sabe sobre a \0bar
peça.
Como você pode ver, a \0
sequência é realmente muito enganadora em uma $'...'
string de estilo; parece um byte nulo dentro da string, mas não acaba funcionando dessa maneira. No seu primeiro exemplo, seu read
comando possui -d $'\0'
. Isso funciona, mas apenas porque -d ''
também funciona! (Esse não é um recurso explicitamente documentado read
, mas suponho que funcione pelo mesmo motivo: ''
é a cadeia vazia, portanto seu byte nulo final vem imediatamente. Está documentado como usando "O primeiro caractere de delim " e acho que até funciona se o "primeiro caractere" já passou do final da string!)-d delim
Mas, como você sabe no seu find
exemplo, é possível que um comando imprima um byte nulo e que esse byte seja canalizado para outro comando que o leia como entrada. Nenhuma parte disso depende do armazenamento de um byte nulo em uma sequência dentro do Bash . O único problema com o seu segundo exemplo é que não podemos usar $'\0'
um argumento para um comando; echo "$file"$'\0'
felizmente poderia imprimir o byte nulo no final, se soubesse que você queria.
Então, em vez de usar echo
, você pode usar printf
, que suporta os mesmos tipos de seqüências de escape que as seqüências de $'...'
estilo. Dessa forma, você pode imprimir um byte nulo sem precisar ter um byte nulo dentro de uma sequência. Isso seria assim:
for file in * ; do printf '%s\0' "$file" ; done \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
ou simplesmente isso:
printf '%s\0' * \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
(Nota: echo
na verdade, também possui um -e
sinalizador que permite processar \0
e imprimir um byte nulo; mas também tenta processar qualquer sequência especial no seu nome de arquivo. Portanto, a printf
abordagem é mais robusta.)
Aliás, existem algumas conchas que não permitem nulo bytes cordas dentro. Seu exemplo funciona bem no Zsh, por exemplo (assumindo as configurações padrão). No entanto, independentemente do seu shell, os sistemas operacionais do tipo Unix não fornecem uma maneira de incluir bytes nulos dentro de argumentos para os programas (como os argumentos do programa são passados como seqüências de caracteres no estilo C), portanto sempre haverá algumas limitações. (Seu exemplo pode funcionar no Zsh apenas porque echo
é um shell embutido, portanto, o Zsh pode invocá-lo sem contar com o suporte do SO para chamar outros programas. Se você usou em command echo
vez de echo
, para que ele ignorasse o embutido e usasse o echo
programa independente no $PATH
, você veria o mesmo comportamento no Zsh e no Bash.)
-d ''
já significa delimitar\0
? Eu encontrei uma explicação aqui: stackoverflow.com/questions/8677546/...