Por que $ '\ 0' é o mesmo que ''?

10

Uma maneira comum de fazer coisas com alguns arquivos é - e não me agrade por isso:

for f in $(ls); do …

Agora, para estar seguro contra arquivos com espaços ou outros caracteres estranhos, seria uma maneira ingênua:

find . -type f -print0 | while IFS= read -r -d '' file; …

Aqui, o -d '' é curto para configurar o ASCII NUL como em -d $'''' .

Mas por que isso acontece? Por que $'%code%' e %code% são iguais? Isso é devido às raízes C do Bash com uma string vazia sendo sempre terminada em null?

    
por slhck 12.01.2013 / 09:15

2 respostas

10

A man page of bash diz:

          -d delim
                 The first character of delim is  used  to  terminate  the
                 input line, rather than newline.

Como as cadeias são normalmente terminadas em null, o primeiro caractere de uma cadeia vazia é o byte nulo. - Faz sentido para mim. :)

A fonte diz:

static unsigned char delim;
[...]
    case 'd':
      delim = *list_optarg;
      break;

Para uma string vazia delim é simplesmente o byte nulo.

    
por 12.01.2013 / 09:25
6

Existem duas deficiências no bash que compensam umas às outras.

Quando você escreve $'-d' , isso é tratado internamente de forma idêntica à string vazia. Por exemplo:

$ a=$'
# a=$'foo
$ a=$'
# a=$'foo%pre%bar'; echo "$a"; echo ${#a}
foo
3
'; echo ${#a} 0
bar'; echo "$a"; echo ${#a} foo 3
'; echo ${#a} 0

Isso ocorre porque o bash internamente armazena todas as strings como strings C , que são terminada em null - um byte nulo marca o final da string. Bash silenciosamente trunca a string para o primeiro byte nulo (que não faz parte da string!).

%pre%

Quando você passa uma string como um argumento para a opção read do read builtin, o bash só olha para o primeiro byte da string. Mas na verdade não verifica se a string não está vazia. Internamente, uma string vazia é representada como uma matriz de bytes de 1 elemento que contém apenas um byte nulo. Então, ao invés de ler o primeiro byte da string, o bash lê este byte nulo.

Então, internamente, o maquinário por trás do ksh -d "" construído funciona bem com bytes nulos; ele continua lendo byte por byte até encontrar o delimitador.

Outras conchas se comportam de maneira diferente. Por exemplo, ash e ksh ignoram os bytes nulos quando lêem a entrada. Com ksh, $'read -d ''' lê até uma nova linha. Os shells são projetados para lidar bem com texto, não com dados binários. Zsh é uma exceção: ele usa uma representação de string que lida com bytes arbitrários, incluindo bytes nulos; em zsh, read -d $'%code%' é uma cadeia de comprimento 1 (mas %code% , estranhamente, se comporta como %code% ).

    
por 14.01.2013 / 02:33

Tags