Voici la réponse courte. Dans la première expression, la virgule est utilisée comme séparateur, donc l'expansion d'accolade n'est que la concaténation des deux sous-expressions imbriquées. Dans la deuxième expression, la virgule est elle-même traitée comme une sous-expression à un seul caractère, de sorte que les expressions de produit sont formées.
Ce qui vous manquait, c'était la définition de la façon dont les extensions de corset sont effectuées. Voici trois références:
Une explication plus détaillée suit.
Vous avez comparé le résultat de cette expression:
$ echo {{a..c},{1..3}}
a b c 1 2 3
au résultat de cette expression:
$ echo {a..c},{1..3}
a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3
Vous dites que c'est difficile à expliquer, c'est-à-dire que c'est contre-intuitif. Ce qui manque, c'est une définition formelle de la façon dont les extensions d'accolade sont traitées. Vous notez que le manuel Bash ne donne pas de définition complète.
J'ai cherché un peu mais je n'ai pas pu trouver la définition manquante (complète, formelle) non plus. Je suis donc allé au code source:
La source contient quelques commentaires utiles. Le premier est un aperçu de haut niveau de l'algorithme d'expansion de l'accolade:
Basic idea:
Segregate the text into 3 sections: preamble (stuff before an open brace),
postamble (stuff after the matching close brace) and amble (stuff after
preamble, and before postamble). Expand amble, and then tack on the
expansions to preamble. Expand postamble, and tack on the expansions to
the result so far.
Le format d'un jeton d'extension d'accolade est donc le suivant:
<PREAMBLE><AMBLE><POSTAMBLE>
Le principal point d'entrée vers l'expansion est une fonction appelée brace_expand
qui est décrite comme suit:
Return an array of strings; the brace expansion of TEXT.
La brace_expand
fonction prend donc une chaîne représentant une expression d'expansion d'accolade et renvoie le tableau de chaînes développées.
En combinant ces deux observations, nous voyons que l'amble est étendu à une liste de chaînes, chacune étant concaténée sur le préambule. Le postambule est ensuite développé en une liste de chaînes et chaque chaîne de la liste de postambules est concaténée sur chaque chaîne de la liste préambule / ambre (c'est-à-dire que le produit des deux listes est formé). Mais cela ne décrit pas comment l'amble et le postamble sont traités. Heureusement, un commentaire le décrit également. L'amble est traité par une fonction appelée expand_amble
dont la définition est précédée du commentaire suivant:
Expand the text found inside of braces. We simply try to split the
text at BRACE_ARG_SEPARATORs into separate strings. We then brace
expand each slot which needs it, until there are no more slots which
need it.
Ailleurs dans le code, nous voyons que BRACE_ARG_SEPARATOR est défini comme une virgule. Cela montre clairement que l'amble est une liste de chaînes séparées par des virgules, dont certaines peuvent également être des expressions d'expansion d'accolade. Ces chaînes forment alors un seul tableau. Enfin, nous pouvons également voir qu'après expand_amble
est appelé, la brace_expand
fonction est alors appelée récursivement sur le postambule. Cela nous donne une description complète de l'algorithme.
Il existe d'autres références (non officielles) qui corroborent cette constatation.
Pour une référence, consultez le wiki Bash Hackers . La section sur la combinaison et l'imbrication ne répond pas tout à fait à votre problème, mais la page donne la syntaxe / grammaire de l'expansion d'accolade, ce qui, je pense, répond à votre question. La syntaxe est donnée par les modèles suivants:
{string1,string2,...,stringN}
{<START>..<END>}
<PREAMBLE>{........}
{........}<POSTSCRIPT>
<PREAMBLE>{........}<POSTSCRIPT>
Et l'analyse est décrite comme suit:
L'expansion d'accolade est utilisée pour générer des chaînes arbitraires. Les chaînes spécifiées sont utilisées pour générer toutes les combinaisons possibles avec les préambules et postscripts optionnels environnants.
Pour une autre référence, jetez un oeil au Guide du débutant Bash , qui a ce qui suit à dire:
Brace expansion is a mechanism by which arbitrary strings may be generated. Patterns to be brace-expanded take the form of an optional PREAMBLE, followed by a series of comma-separated strings between a pair of braces, followed by an optional POSTSCRIPT. The preamble is prefixed to each string contained within the braces, and the postscript is then appended to each resulting string, expanding left to right.
Donc, pour analyser les expressions d'expansion d'accolade, nous allons de gauche à droite, développant chaque expression et formant des produits successifs (en ce qui concerne le fonctionnement de la concaténation de chaînes).
Considérons maintenant votre première expression:
{{a..c},{1..3}}
Dans la langue du Wiki du Bash Hacker, cela correspond à la première forme:
{string1,string2,...,stringN}
Où N=2
, string1={a..c}
et string2={1..3}
- les extensions de l'accolade intérieure sont effectuées en premier et chacune d'elles est de la forme {<START>..<END>}
. Alternativement, nous pouvons dire que c'est une expression d'expansion d'accolade qui consiste uniquement en un amble (pas de préambule ou de postambule). L'amble est une liste séparée par des virgules, nous parcourons donc la liste un emplacement à la fois et effectuons des extensions supplémentaires si nécessaire. Aucun produit n'est formé car il n'y a pas d'expressions adjacentes (la virgule est utilisée comme séparateur).
Voyons maintenant votre deuxième expression:
{a..c},{1..3}
Dans la langue du Wiki du Bash Hacker, cette expression correspond à la forme:
{........}<POSTSCRIPT>
où le post-scriptum est la sous-expression ,{1..3}
. Alternativement, nous pouvons dire que cette expression a un amble ( {a..c}
) et un postamble ( ,{1..3}
). L'ambre est développé dans la liste a b c
, puis chacun d'eux est concaténé avec chacune des chaînes dans l'expansion du postambule. Le postambule est traité de manière récursive: il a un préambule ,
et un ambre de {1..3}
. Ceci est étendu à la liste ,1 ,2 ,3
. Les deux listes a b c
et ,1 ,2 ,3
sont ensuite combinées pour former la liste des produits a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3
.
Cela pourrait aider à donner une description pseudo-algébrique de la façon dont ces expressions sont analysées, où les crochets "[]" désignent les tableaux, "+" dénote la concaténation des tableaux et "*" dénote le produit cartésien (en ce qui concerne la concaténation).
Voici comment la première expression est développée (une étape par ligne):
{{a..c},{1..3}}
{a..c} + {1..3}
[a b c] + [1 2 3]
a b c 1 2 3
Et voici comment la deuxième expression est développée:
{a..c},{1..3}
{a..c} * ,{1..3}
[a b c] * [,1 ,2 ,3]
a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3