Une façon courante de faire les choses avec quelques fichiers est — et ne me frappez pas pour cela:
for f in $(ls); do …
Maintenant, pour être à l'abri des fichiers contenant des espaces ou d'autres caractères étranges, une manière naïve serait de faire:
find . -type f -print0 | while IFS= read -r -d '' file; …
Ici, le -d ''
est court pour définir le NUL ASCII comme dans -d $'\0'
.
Mais pourquoi en est-il ainsi? Pourquoi ''
et $'\0'
la même chose? Est-ce dû aux racines C de Bash avec une chaîne vide toujours terminée par un caractère nul?
for f in *
plutôt que d'analyserls
.for i in $(ls)
c'est terriblement stupide - j'ai presque honte de l'avoir utilisé comme mauvais exemple ici.find … -exec
au lieu de boucler autour des fichiers, ce qui fonctionne dans la plupart des cas où vous utiliseriez une telle boucle for à la place. Ici,find
s'occupe de tout pour vous.Réponses:
Le
man page of bash
lit:Étant donné que les chaînes sont généralement terminées par null, le premier caractère d'une chaîne vide est l'octet nul. - Ça a du sens pour moi. :)
La source lit:
Pour une chaîne vide
delim
est simplement l'octet nul.la source
split()
elle se divisera entre chaque caractère. Je soupçonne qu'un «pour des raisons historiques» pourrait être la meilleure explication que nous puissions obtenir.'\0'
avec'X\0'
devrait vous donner'X\0'
, si c'est bien fait. Cela n'a pas grand-chose à voir avec les fonctions de haut niveau dans des langages tels que JavaScript @dondelim = *list_optarg;
explique pourquoi il en est ainsi.''
-ils$'\0'
les mêmes?", Michas a donné l'explication immédiate de "c'est ce que fait le code". J'ai décrit une autre façon de gérer la chaîne vide que je considérais comme tout aussi raisonnable et j'ai suggéré que choisir l'un ou l'autre était simplement une question de convention ou de hasard.Il y a deux lacunes dans bash qui se compensent.
Lorsque vous écrivez
$'\0'
, cela est traité en interne de manière identique à la chaîne vide. Par exemple:C'est parce que bash stocke en interne toutes les chaînes sous forme de chaînes C , qui se terminent par un caractère nul - un octet nul marque la fin de la chaîne. Bash tronque silencieusement la chaîne au premier octet nul (qui ne fait pas partie de la chaîne!).
Lorsque vous passez une chaîne comme argument à l'
-d
option de la commanderead
intégrée, bash ne regarde que le premier octet de la chaîne. Mais il ne vérifie pas réellement que la chaîne n'est pas vide. En interne, une chaîne vide est représentée comme un tableau d'octets à 1 élément qui contient juste un octet nul. Ainsi, au lieu de lire le premier octet de la chaîne, bash lit cet octet nul.Ensuite, en interne, la machinerie derrière la
read
fonction intégrée fonctionne bien avec des octets nuls; il continue à lire octet par octet jusqu'à ce qu'il trouve le délimiteur.D'autres obus se comportent différemment. Par exemple, ash et ksh ignorent les octets nuls lorsqu'ils lisent l'entrée. Avec ksh,
ksh -d ""
lit jusqu'à une nouvelle ligne. Les shells sont conçus pour bien gérer le texte, pas les données binaires. Zsh est une exception: il utilise une représentation sous forme de chaîne qui accepte des octets arbitraires, y compris des octets nuls; en zsh,$'\0'
est une chaîne de longueur 1 (maisread -d ''
, bizarrement, se comporte commeread -d $'\0'
).la source
read
changé dans bash 4.3 de sorte qu'il ignore maintenant les octets nuls. Par exemple,read x< <(printf a\\0a)
définit surx
auaa
lieu dea
.