Expansion d'une variable shell et effet de glob et split sur elle

18

Ce post contient en fait deux questions distinctes, mais je pense que les regrouper donnera un peu plus de contexte. J'ai parcouru cette question sur les citations autour des variables mais je ne comprends pas très bien ce que signifie l' expansion des variables en premier lieu. Ma première question est donc:

  1. Qu'est-ce que l' expansion variable sous Unix / Linux?

Une deuxième partie de ma question concerne les termes suivants:

  1. glob
  2. Divisé

Que signifient les éléments ci-dessus et comment affectent-ils l'expansion variable? La réponse à la question d'origine mentionne ce qui suit:

Considérez l'absence de guillemets (dans les contextes de liste) comme l'opérateur split + glob.

Comme si echo $ test était echo glob (split ("$ test")).

Je n'ai pas trouvé de réponses qui traitent directement du concept de globalisation et de fractionnement, mais utilisent plutôt ces termes directement pour répondre à d'autres questions comme celle- ci .

Geek
la source

Réponses:

15

L'expansion variable (le terme standard est l' expansion des paramètres , et il est aussi parfois appelé substitution de variable ) signifie essentiellement remplacer la variable par sa valeur. Plus précisément, cela signifie remplacer la $VARIABLEconstruction (ou ${VARIABLE}ou ${VARIABLE#TEXT}ou d'autres constructions) par un autre texte qui est construit à partir de la valeur de la variable. Cet autre texte est l'expansion de la variable.

Le processus d'expansion se déroule comme suit. (Je ne parle que du cas commun, certains paramètres et extensions du shell modifient le comportement.)

  1. Prenez la valeur de la variable, qui est une chaîne. Si la variable n'est pas définie, utilisez la chaîne vide.
  2. Si la construction inclut une transformation, appliquez-la. Par exemple, si la construction est ${VARIABLE#TEXT}et que la valeur de la variable commence par TEXT, supprimez-la TEXTdu début de la valeur.
  3. Si le contexte appelle un seul mot (par exemple entre guillemets doubles, ou dans le côté droit d'une affectation, ou dans un document ici), arrêtez-vous ici. Sinon, passez aux étapes suivantes.
  4. Divisez la valeur en mots séparés à chaque séquence d'espaces. (La variable IFSpeut être modifiée pour se diviser en caractères autres que les espaces.) Le résultat n'est donc plus une chaîne, mais une liste de chaînes. Cette liste peut être vide si la valeur ne contient que des espaces.
  5. Traitez chaque élément de la liste comme un motif générique de nom de fichier, c'est-à-dire un glob . Si le modèle correspond à certains fichiers, il est remplacé par la liste des noms de fichiers correspondants, sinon il est laissé seul.

Par exemple, supposons que la variable foocontienne a* b* c*et que le répertoire courant contienne les fichiers bar, bazet paz. ${foo#??}Est ensuite développé comme suit:

  1. La valeur de la variable est la chaîne de 8 caractères a* b* c*.
  2. #??signifie supprimer les deux premiers caractères, ce qui donne la chaîne de 6 caractères  b* c*(avec un espace initial).
  3. Si l'expansion est dans un contexte de liste (c'est-à-dire pas entre guillemets doubles ou dans un autre contexte similaire), continuez.
  4. Divisez la chaîne en mots séparés par des espaces, ce qui donne une liste de deux chaînes: b*et c*.
  5. La chaîne b*, interprétée comme un modèle, correspond à deux fichiers: baret baz. La chaîne c*ne correspond à aucun fichier, elle est donc laissée seule. Le résultat est une liste de trois chaînes: bar, baz, c*.

Par exemple, echo ${foo#??}imprime bar baz c*(la commande echojoint ses arguments avec un espace entre les deux).

Pour plus de détails, voir:

Gilles 'SO- arrête d'être méchant'
la source
2
Notez qu'il appelle l' expansion des paramètres parce qu'il applique aux variables ( $var) et d' autres types de paramètres comme $1, $#, $?, $-...
Stéphane Chazelas
12

glob / split

Je prends d'abord le glob / split. @ La réponse de Stéphane à laquelle vous avez lié est d'utiliser ces termes dans un sens général. Ce ne sont pas des commandes réelles ou quelque chose comme ça, juste des pseudo-opérations.

Le split("$test")diviserait le contenu de "$ test" en un "tableau" d'éléments.

Le glob(...)prendrait alors soin de développer n'importe lequel de ces éléments contenant des caractères de globalisation du shell tels que *ou des plages [1-2].

Exemple

Disons que notre chaîne $testest la suivante.

$ test="afile[1-2] afile[3-5]"

Disons également que nous avons un répertoire contenant quelques fichiers.

$ ls -1
afile1
afile2
afile3
afile4
afile5

Maintenant, si nous essayons de l'écho sans guillemets, vous devriez remarquer que notre chaîne a été divisée en espaces, puis tous les caractères globulaires ont été développés.

$ echo $test
afile1 afile2 afile3 afile4 afile5

Cependant, si nous devions citer la variable lorsque nous la transmettions comme argument, echonous obtiendrions la chaîne littérale d'origine.

$ echo "$test"
afile[1-2] afile[3-5]

expansion variable

Le terme expansion variable est destiné à couvrir l'opération de base que le shell effectue dans le cadre de ses opérations de base. Le shell est responsable de l'analyse de l'entrée, puis de l'exécution de cette entrée une fois qu'elle est jugée syntaxiquement correcte.

Dans notre exemple précédent. Lorsque la variable a $testété présentée comme echonon citée, nous disions au shell d'aller de l'avant et de diviser ces arguments puis de les globaliser.

Quand il a été cité, nous désactivions essentiellement cette fonctionnalité avec les variables que nous avons enveloppées de guillemets doubles.

Exemple

Voici quelques exemples supplémentaires de globbing et de split.

glob / split se produit automatiquement

$ echo file{1..3}
file1 file2 file3

$ echo file{1..3} dir{a..b}
file1 file2 file3 dira dirb

$ echo dir{z..w} file{A..D}
dirz diry dirx dirw fileA fileB fileC fileD

$ echo dir{z..w} file{A..B} fileC
dirz diry dirx dirw fileA fileB fileC

glob / fractionnement désactivé via des guillemets doubles

$ echo "dir{z..w} file{A..B} fileC"
dir{z..w} file{A..B} fileC

$ echo "dir{z..w} file{A..B}"
dir{z..w} file{A..B}
slm
la source
Je ne savais pas que les gammes fonctionnaient également dans l'ordre inverse.
Joe