for i in $(xrandr); do echo "$i" ; donefor i in "$(xrandr)"; do echo "$i"; donefor i in "$(xrandr)"; do echo $i; done
Je comprends pourquoi 1 diffère de 2. Mais pourquoi 3 donne-t-il une sortie différente de 2 ? Veuillez également expliquer la sortie. Comment fonctionnent les guillemets sur les retours à la ligne ?
Réponse acceptée :
Une variable sans guillemets (comme dans $var ) ou substitution de commande (comme dans $(cmd) ou `cmd` ) est le split+glob opérateur dans les coques de type Bourne.
C'est-à-dire que leur contenu est divisé en fonction de la valeur actuelle du $IFS variable spéciale (qui contient par défaut les caractères espace, tabulation et saut de ligne)
Et puis chaque mot résultant de ce fractionnement est soumis à la génération du nom de fichier (également connu sous le nom de globbing ou expansion du nom de fichier ), c'est-à-dire qu'ils sont considérés comme des modèles et sont étendus à la liste des fichiers correspondant à ce modèle.
Donc dans for i in $(xrandr) , le $(xrandr) , car il n'est pas entre guillemets, est divisé en séquences d'espaces, de tabulations et de sauts de ligne. Et chaque mot résultant de ce fractionnement est vérifié pour les noms de fichiers correspondants (ou laissé tel quel s'ils ne correspondent à aucun fichier), et for les boucle tous.
Dans for i in "$(xrandr)" , nous n'utilisons pas l'opérateur split+glob comme substitution de commande est entre guillemets, il y a donc une passe dans la boucle sur une value :la sortie de xrandr (sans les caractères de fin de ligne qui substitution de commande bandes).
Cependant dans echo $i , $i est à nouveau sans guillemets, donc à nouveau le contenu de $i est divisé et soumis à la génération du nom de fichier et ceux-ci sont passés en tant qu'arguments séparés au echo commande (et echo affiche ses arguments séparés par des espaces).
Donc leçon apprise :
- si vous ne voulez pas séparer les mots ou génération de nom de fichier , mettez toujours entre parenthèses les développements de variables et les substitutions de commandes
- si vous voulez séparer les mots ou génération de nom de fichier , laissez-les sans guillemets mais définissez
$IFSen conséquence et/ou activer ou désactiver la génération du nom de fichier si nécessaire (set -f,set +f).
Typiquement, dans votre exemple ci-dessus, si vous voulez boucler sur la liste de mots séparés par des blancs dans la sortie de xrandr , vous devez :
- laisser
$IFSà sa valeur par défaut (ou annulez-la) pour diviser sur des blancs - Utilisez
set -fpour désactiver la génération de nom de fichier sauf si vous êtes sûr quexrandrne produit jamais de*ou?ou[caractères (qui sont des caractères génériques utilisés dans les modèles de génération de noms de fichiers)
Et puis n'utilisez que l'opérateur split + glob (ne laissez que la substitution de commande ou l'expansion de variable sans guillemets) dans le in partie du for boucle :
set -f; unset -v IFS
for i in $(xrandr); do whatever with "$i"; done
Si vous voulez boucler sur les lignes (non vides) du xrandr sortie, vous devez définir $IFS au caractère de saut de ligne :
IFS='
'