0 votes

Les résultats de la recherche ne peuvent pas être encapsulés dans des guillemets

Sous Linux, la gestion des espaces lorsque j'utilise les résultats find ne nécessite que de mettre la variable entre guillemets. Cela ne fonctionne pas sous OS X. Ce code, par exemple, ne fonctionne pas :

for file in $(find . -name "*.txt")
do
    ls -l "${file}"
done

Même entre guillemets, les parties de noms de fichiers séparées par des espaces sont traitées comme leur propre résultat. Comment résoudre ce problème ?

2voto

nohillside Points 82672

De Les pièges du Bash (qui explique également en détail pourquoi for file in (find ...); do ne fonctionne pas) :

Lors de l'utilisation de la fonction de recherche l'utiliser correctement ex. utiliser -exec

find . -type f -exec some command {} \;

Au lieu de ls considérer,

for i in *.mp3; do    # Better! and...
    some command "$i" # ...always double-quote expansions!
done

Les interpréteurs de commandes POSIX tels que Bash disposent d'une fonction de globbing spécialement conçue à cet effet, qui permet à l'interpréteur de commandes de développer des motifs en une liste de noms de fichiers correspondants. Il n'est pas nécessaire d'interpréter les résultats d'un utilitaire externe. Comme le globbing est la toute dernière étape de l'expansion, chaque correspondance du motif *.mp3 s'étend correctement en un mot distinct et n'est pas soumis aux effets d'une expansion sans guillemets. (Si vous avez besoin de traiter des fichiers de manière récursive, voir Utilisation deFind .)

Question : Que se passe-t-il s'il n'y a pas de *.mp3 -fichiers dans le répertoire actuel ? La boucle for est alors exécutée une fois, avec i="*.mp3" ce qui n'est pas le comportement attendu ! La solution consiste à vérifier s'il existe un fichier correspondant :

# POSIX
for i in *.mp3; do
    [ -e "$i" ] || continue
    some command "$i"
done

Notez les guillemets autour de $i dans le corps de la boucle ci-dessus.

1voto

Michael Zhou Points 167

Votre code ne fonctionne pas sous OS X ou Linux.

for file in $(find . -name "*.txt")
do
    ls -l "${file}"
done

L'interpréteur de commandes effectue d'abord l'expansion de la substitution de la commande $(find . -name "*.txt") Les résultats sont les suivants file with spaces\nanother file with spaces et ainsi de suite. Maintenant, l'interpréteur de commandes effectue word spitting sur la base de la valeur de IFS - le séparateur de champ interne. La valeur est généralement l'espace blanc, la tabulation et la nouvelle ligne.

Exécutez le code suivant :

for file in $(find . -name "*.txt")
do
    echo "${file}"
done

Modifions maintenant le IFS au seul caractère de retour à la ligne.

IFS='
'
for file in $(find . -name "*.txt")
do
    ls -l -- "${file}"
done

Votre code fonctionnera, mais je vous conseille de ne pas modifier les éléments suivants IFS et trouver des solutions alternatives.

GNU find et BSD find sont tous deux très robustes et peuvent traiter les noms de fichiers comportant des espaces. Vous pouvez éviter la boucle et obtenir des résultats similaires avec une seule ligne

find . -name "*.txt" -ls

LesApples.com

LesApples est une communauté de Apple où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres utilisateurs d'appareils Apple, poser vos propres questions ou résoudre celles des autres.

Powered by:

X