Quand {a, b, c} est-il développé dans bash, quand ne l'est-il pas?

13

Un script bash qui contient

for i in {a,b}-{1,2}; do
  echo $i;
done

impressions

a-1
a-2
b-1
b-2

une fois exécuté. C'est ce que j'attendais - à mesure que la {a,b}construction est développée.

Cependant, quand (un autre) script contient

v={a,b}-{1,2}
echo $v

il imprime

{a,b}-{1,2}

ce qui n'est pas ce que j'attendais. Je m'attendais à ce qu'il s'imprime a-1 a-2 b-1 b-2. De toute évidence, la {a,b}construction n'est pas développée.

Je peux le faire grandir comme ça

v=$(echo {a,b}-{1,2})

Sur la base de ces observations, j'ai deux questions: 1) quand la {a,b}construction est-elle développée? 2) est $(echo {a,b}-{1,2})la meilleure façon de déclencher une expansion si nécessaire?

René Nyffenegger
la source
1
Ceci est, au moins, cohérent avec le fait que vous ne pouvez pas créer une variable de tableau avec un simple =. Par exemple, v=a-1 a-2ne fonctionnera pas.
grochmal
@grochmal - c'est parce que vous attribuez une valeur scalaire. v=a-1 a-2signifie assign 'a-1' to variable v and run 'a-2' v=(a-1 a-2)attribue le tableau à la variable v. v+=(b-1 b-2)s'y ajoute.
cas

Réponses:

15

Le manuel de Bash dit que:

SIMPLE COMMAND EXPANSION
When a simple command is executed, the shell performs the following
expansions, assignments, and redirections, from left to right.
[...]
4. The  text  after the = in each variable assignment undergoes tilde
   expansion, parameter expansion, command substitution, arithmetic
   expansion, and quote removal before being assigned to the variable.

L'extension d'accolade n'est pas dans la liste, elle n'est donc pas effectuée pour l'affectation v={a,b}-{1,2}. Comme mentionné par @Wildcard, l'expansion simple v=a-1 v=b-1 ...serait de toute façon insensée.

De plus, lors de l'exécution de echo $v, les règles suivantes s'appliquent:

EXPANSION
Expansion is performed on the command line after it has been split
into words. [...]

The order of expansions is: brace expansion; tilde expansion, 
parameter and variable expansion, arithmetic expansion, and command
substitution (done in a left-to-right fashion); word splitting; and
pathname expansion.

L'expansion d'accolade se produit avant l'expansion variable, donc les accolades affectées à $vne sont pas développées.

Mais vous pouvez faire des trucs comme ça:

$ var_this=foo var_that=bar
$ echo $var_{this,that}
foo bar

Le développer avec $(echo ...)devrait fonctionner si vous n'avez aucun espace dans la chaîne à développer, et ne rencontrerez donc pas de problèmes avec le fractionnement de mots. Une meilleure façon pourrait être d'utiliser une variable de tableau si vous le pouvez.

Par exemple, enregistrez l'expansion dans un tableau et exécutez une commande avec les valeurs étendues:

$ v=( {a,b}-{1,2} )
$ some_command "${v[@]}"
ilkkachu
la source
5

Un point intéressant. L'extrait suivant est peut-être utile man bash:

Une variable peut être affectée à une instruction du formulaire

      nom = [ valeur ]

Si aucune valeur n'est donnée, la variable se voit affecter la chaîne nulle. Toutes les valeurs subissent une expansion de tilde, une expansion de paramètres et de variables, une substitution de commande, une expansion arithmétique et une suppression de devis (voir EXPANSION ci-dessous).

Notez que l'expansion d'accolade n'est PAS mentionnée dans la liste.

Cependant, cela laisse encore une question, à savoir: comment le shell sait-il qu'il s'agit d'une affectation variable et donc non soumise à l'expansion d'accolade? Ou plus précisément, où la séquence d'analyse est-elle clarifiée et codifiée de telle sorte que le shell est défini pour identifier les affectations de variables avant de gérer l'expansion de l'accolade? (C'est évidemment ainsi que cela bashfonctionne, mais je n'ai pas trouvé la ligne exacte de la documentation décrivant cela.)

Caractère générique
la source
1
Peut - être ça ? "2. Les mots qui ne sont pas des affectations de variables ou des redirections sont développés (voir Extensions de shell)."
Jeff Schaller
@JeffSchaller, vous avez raison. En fait, il est préférable de répondre à cette question en lisant simplement la section "EXPANSION DE COMMANDE SIMPLE" ( LESS=+/SIMPLE man bash).
Wildcard
0

selon mes connaissances, le {a, b, c} est développé lorsqu'il est directement répercuté ou utilisé avec une commande, par exemple: mkdir ~ / {a, b, c}, mais lorsqu'il est défini sur une variable, il doit être évalué avant l'écho ou en l'utilisant comme argument!

u@h:~$ echo {a,b}-{1,2}
a-1 a-2 b-1 b-2
u@h:~$ v={a,b}-{1,2}
u@h:~$ echo $v
{a,b}-{1,2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2

puisque vous avez "a" suivi de "b" dans l'ordre alpha [az] et "1" suivi de "2" dans l'ordre dec [0-9]: vous pouvez utiliser le double point ".." insteed of comma ", "

u@h:~$ echo {a..b}-{1..2}
a-1 a-2 b-1 b-2
u@h:~$ v={a..b}-{1..2}
u@h:~$ echo $v
{a..b}-{1..2}
u@h:~$ eval echo $v
a-1 a-2 b-1 b-2
Jonas
la source
1
La question est de savoir pourquoi la chaîne littérale "a-1 a-2 b-1 b-2" vn'a pas été définie . Ou du moins pourquoi aucune erreur n'a été générée lorsque vous tapez la commande: v=a-1 v=a-2 v=b-1 v=b-2(à laquelle vous vous attendez à ce que l'affectation de variable soit étendue). C'est une bonne question; cela n'y répond pas vraiment.
Wildcard
@SatoKatsura, que signifie "expansion générique"? Il y a l'expansion des paramètres, l'expansion des noms de chemin et l'expansion des accolades - dont vous pourriez vous référer à, et qui sont toutes différentes. Ou vouliez-vous dire la division des mots?
Wildcard
0

L'affectation à une variable dans bash ne développe pas l'expression.

Pour ce petit script, x contiendra "*"et non l'extension de "*":

#!/bin/bash
x=*
echo "$x"

Cependant, certaines valeurs sont développées, réf. la belle réponse d'ilkkachu.

Les expressions sont développées lorsqu'elles sont évaluées.

Comme ça:

x=$(echo *)        # <-- evaluation of "*"
echo "$x"

Ou comme ça:

x=*
echo $x            # <-- evaluation of $x

Ou comme ça:

x=*
eval echo "$x"     # <-- evaluation of `echo *`

Le déclenchement $()est assez courant et je pense qu'il est préférable à eval, mais le mieux est probablement de ne pas déclencher d'évaluation du tout, jusqu'à ce que la variable soit réellement utilisée dans une commande.

Alexandre
la source