for i in $(xrandr); do echo "$i" ; done
for i in "$(xrandr)"; do echo "$i"; done
for 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
$IFS
en 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 -f
pour désactiver la génération de nom de fichier sauf si vous êtes sûr quexrandr
ne 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='
'