Idéalement, vous ne le faites pas du tout de cette façon, car il est toujours difficile d'analyser correctement les noms de fichiers dans un script shell (réparez-le pour les espaces, vous aurez toujours des problèmes avec d'autres caractères intégrés, en particulier la nouvelle ligne). Ceci est même répertorié comme la première entrée de la page BashPitfalls.
Cela dit, il existe un moyen de faire presque ce que vous voulez :
oIFS=$IFS
IFS=$'\n'
find . -name '*.txt' | while read -r i; do
# use "$i" with whatever you're doing
done
IFS=$oIFS
N'oubliez pas de citer également $i
lors de son utilisation, pour éviter que d'autres choses n'interprètent les espaces plus tard. N'oubliez pas également de définir $IFS
de retour après l'avoir utilisé, car ne pas le faire entraînera des erreurs déconcertantes plus tard.
Ceci a une autre mise en garde :que se passe-t-il à l'intérieur du while
loop peut avoir lieu dans un sous-shell, selon le shell exact que vous utilisez, de sorte que les paramètres variables peuvent ne pas persister. Le for
la version boucle évite cela mais au prix que, même si vous appliquez le $IFS
solution pour éviter les problèmes d'espaces, vous aurez alors des ennuis si le find
renvoie trop de fichiers.
À un moment donné, la solution correcte pour tout cela devient de le faire dans un langage tel que Perl ou Python au lieu de shell.
Utilisez find -print0
et dirigez-le vers xargs -0
, ou écrivez votre propre petit programme C et dirigez-le vers votre petit programme C. C'est ce que -print0
et -0
ont été inventés pour.
Les scripts shell ne sont pas la meilleure façon de gérer les noms de fichiers contenant des espaces :vous pouvez le faire, mais cela devient maladroit.
Vous pouvez définir le "séparateur de champ interne" (IFS
) à autre chose qu'un espace pour le fractionnement de l'argument de la boucle, par exemple
ORIGIFS=${IFS}
NL='
'
IFS=${NL}
for i in $(find . -name '*.txt'); do
IFS=${ORIGIFS}
#do stuff
done
IFS=${ORIGIFS}
J'ai réinitialisé IFS
après son utilisation en trouvaille, surtout parce que ça a l'air sympa, je trouve. Je n'ai vu aucun problème à le définir sur nouvelle ligne, mais je pense que c'est "plus propre".
Une autre méthode, selon ce que vous voulez faire avec la sortie de find
, est soit d'utiliser directement -exec
avec le find
ou utilisez -print0
et dirigez-le vers xargs -0
. Dans le premier cas find
prend soin de l'échappement du nom de fichier. Dans le -print0
cas, find
imprime sa sortie avec un séparateur nul, puis xargs
se divise à ce sujet. Comme aucun nom de fichier ne peut contenir ce caractère (ce que je sais), c'est toujours sûr également. Ceci est surtout utile dans des cas simples; et n'est généralement pas un excellent substitut pour un for
complet boucle.