Uma maneira comum de fazer as coisas com alguns arquivos é - e não me bata por isso:
for f in $(ls); do …
Agora, para estar seguro contra arquivos com espaços ou outros caracteres estranhos, uma maneira ingênua seria:
find . -type f -print0 | while IFS= read -r -d '' file; …
Aqui, -d ''
é a abreviação de definir o ASCII NUL como em -d $'\0'
.
Mas porque é isso? Por que são ''
e $'\0'
os mesmos? Isso ocorre devido às raízes C do Bash, com uma string vazia sempre sendo terminada em nulo?
for f in *
vez de analisarls
.for i in $(ls)
é terrivelmente estúpido - estou quase com vergonha de ter usado isso como um mau exemplo aqui.find … -exec
vez de repetir arquivos, o que funciona na maioria dos casos em que você usaria um loop for. Aqui,find
cuida de tudo para você.Respostas:
As
man page of bash
leituras:Como as strings geralmente são terminadas em nulo, o primeiro caractere de uma string vazia é o byte nulo. - Faz sentido para mim. :)
A fonte diz:
Para uma sequência vazia,
delim
é simplesmente o byte nulo.fonte
split()
ela será dividida entre cada caractere. Suspeito que "por razões históricas" possa ser a melhor explicação que podemos obter.'\0'
com'X\0'
deve dar a você'X\0'
, se bem feito. Isto não tem muito a ver com funções de alto nível em linguagens como JavaScript @dondelim = *list_optarg;
deixa claro por que é assim.''
e são$'\0'
iguais?", Michas deu a explicação aproximada de "é isso que o código faz". Descrevi uma maneira alternativa de lidar com a cadeia vazia que considerava igualmente razoável e sugeri que escolher uma ou outra era simplesmente uma questão de convenção ou acontecimento.Existem duas deficiências no bash que se compensam.
Quando você escreve
$'\0'
, isso é tratado internamente de forma idêntica à sequência vazia. Por exemplo:Isso ocorre porque internamente o bash armazena todas as seqüências de caracteres como C , com terminação nula - um byte nulo marca o final da sequência. O Bash silenciosamente trunca a string para o primeiro byte nulo (que não faz parte da string!).
Quando você passa uma string como argumento para a
-d
opção doread
builtin, o bash analisa apenas o primeiro byte da string. Mas na verdade não verifica se a string não está vazia. Internamente, uma sequência vazia é representada como uma matriz de bytes de 1 elemento que contém apenas um byte nulo. Portanto, em vez de ler o primeiro byte da string, o bash lê esse byte nulo.Em seguida, internamente, o mecanismo por trás do
read
built-in funciona bem com bytes nulos; ele continua lendo byte a byte até encontrar o delimitador.Outras conchas se comportam de maneira diferente. Por exemplo, ash e ksh ignoram bytes nulos quando lêem a entrada. Com ksh,
ksh -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,$'\0'
é uma sequência de comprimento 1 (masread -d ''
, estranhamente, se comporta comoread -d $'\0'
).fonte
read
mudou no bash 4.3 para que agora pule bytes nulos. Por exemplo,read x< <(printf a\\0a)
definex
para emaa
vez dea
.