$ touch "aaaaaa bbbbbbb ccc" dddddd "eeeee^Mffffff" zzzzz $ for i in $(ls); do echo "[$i]"; done [aaaaaa] [bbbbbbb] [ccc] [dddddd] ffffff] [zzzzz] $ for i in *; do echo "[$i]"; done [aaaaaa bbbbbbb ccc] [dddddd] ffffff] [zzzzz]
Mettons nous deux secondes dans la peau d'un shell basique qui analyse ligne par ligne la ligne de commande. Il réalise les opérations suivantes :
- Vérifie la syntaxe,
- S'il y a des caractères d'expansion (Joker par exemple), on déroule ce caractère puis on échappe les caractères importants,
- Développement/Expansion des variables (Remplacer
$fooou$(find...)par sa valeur), - Découpage des arguments, (Découper les arguments en "mots"),
- Éxécution de la commande,
Maintenant, prenons l'exemple suivant :
$ foo="maou fait le chat"
$ for i in $foo; do
echo $i;
done
Pour la ligne "for i in $foo; do", voici le
traitement :
- Syntaxe OK
- Pas de Joker,
- On remplace la variable par sa valeur :
for i in maou fait le chat; do - On découpe ce qui est entre "in" et le
point-virgule (;),
Les mots sont séparés par un des caractères contenus dans$IFSfor i in "maou" "fait" "le" "chat"; do - On éxécute la boucle.
$ireçoit alors les valeurs "maou", "fait", "le", "chat"
Appliquons cela à la ligne suivante :
$ for i in $(ls); do
... ;
done
Dans un premier temps, $(ls) va être étendue, puis découpé en
mots. Aucun échappement de caractère ne sera fait, c'est là le
problème, donc les mots seront découpés avec les séparateurs
d'$IFS.
Alors que pour la ligne suivante :
$ for i in *; do
... ;
done
Le shell rencontre un caractère Joker (*), donc il fait
une expansion de nom de fichier, et en profite pour échapper tous les
caractères qui ont une signification (Tout ce qui est dans
$IFS entre autre).
Lorsque le shell passera à l'étape suivante, il ne découpera pas les mots avec les caractères espaces et tout ça car ils sont échappés...