Hier ist die kurze Antwort. Im ersten Ausdruck wird das Komma als Trennzeichen verwendet, sodass die Klammererweiterung nur die Verkettung der zwei verschachtelten Unterausdrücke ist. Im zweiten Ausdruck wird das Komma selbst als ein Ein-Zeichen subexpression behandelt, so Produktausdrücke werden gebildet.
Was Ihnen fehlte, war die Definition, wie Klammer-Erweiterungen durchgeführt werden. Hier sind drei Referenzen:
Eine detailliertere Erklärung folgt.
Sie haben das Ergebnis dieses Ausdrucks verglichen:
$ echo {{a..c},{1..3}}
a b c 1 2 3
zum Ergebnis dieses Ausdrucks:
$ echo {a..c},{1..3}
a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3
Sie sagen, dass dies schwer zu erklären ist, dh dass dies kontraintuitiv ist. Was fehlt, ist eine formale Definition, wie Klammer-Erweiterungen verarbeitet werden. Sie stellen fest, dass das Bash-Handbuch keine vollständige Definition enthält.
Ich habe ein wenig gesucht, aber auch die fehlende (vollständige, formale) Definition nicht gefunden. Also ging ich zum Quellcode:
Die Quelle enthält einige nützliche Kommentare. Zunächst ein allgemeiner Überblick über den Klammererweiterungsalgorithmus:
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.
Das Format eines Klammer-Erweiterungs-Tokens lautet also wie folgt:
<PREAMBLE><AMBLE><POSTAMBLE>
Der Haupteinstiegspunkt für die Erweiterung ist eine Funktion, brace_expand
die wie folgt beschrieben wird:
Return an array of strings; the brace expansion of TEXT.
Die brace_expand
Funktion nimmt also eine Zeichenfolge, die einen Klammererweiterungsausdruck darstellt, und gibt das Array der erweiterten Zeichenfolgen zurück.
Wenn wir diese beiden Beobachtungen kombinieren, sehen wir, dass der Amble zu einer Liste von Strings erweitert wird, von denen jeder mit der Präambel verkettet ist. Die Postambel wird dann zu einer Liste von Zeichenfolgen erweitert, und jede Zeichenfolge in der Postambel-Liste wird mit jeder Zeichenfolge in der Präambel / Amble-Liste verkettet (dh das Produkt der beiden Listen wird gebildet). Dies beschreibt jedoch nicht, wie das Amble und das Postamble verarbeitet werden. Zum Glück gibt es einen Kommentar, der das ebenfalls beschreibt. Das Amble wird von einer Funktion verarbeitet, expand_amble
deren Definition der folgende Kommentar vorausgeht:
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.
An anderer Stelle im Code sehen wir, dass BRACE_ARG_SEPARATOR als Komma definiert ist. Dies macht deutlich, dass es sich bei dem Amble um eine durch Kommas getrennte Liste von Zeichenfolgen handelt, von denen einige auch geschweifte Ausdrücke sein können. Diese Zeichenfolgen bilden dann ein einzelnes Array. Schließlich können wir auch sehen, dass expand_amble
die brace_expand
Funktion nach dem Aufruf rekursiv in der Postambel aufgerufen wird. Dies gibt uns eine vollständige Beschreibung des Algorithmus.
Es gibt einige andere (inoffizielle) Hinweise, die diese Feststellung bestätigen.
Eine Referenz finden Sie im Bash Hackers Wiki . Der Abschnitt über das Kombinieren und Verschachteln geht nicht ganz auf Ihr Problem ein, aber die Seite enthält die Syntax / Grammatik der Klammererweiterung, die Ihrer Meinung nach Ihre Frage beantwortet. Die Syntax ergibt sich aus folgenden Mustern:
{string1,string2,...,stringN}
{<START>..<END>}
<PREAMBLE>{........}
{........}<POSTSCRIPT>
<PREAMBLE>{........}<POSTSCRIPT>
Und das Parsen wird wie folgt beschrieben:
Die geschweifte Klammer wird zum Generieren beliebiger Zeichenfolgen verwendet. Die angegebenen Zeichenfolgen werden verwendet, um alle möglichen Kombinationen mit den optionalen umgebenden Präambeln und Nachskripten zu generieren .
Eine weitere Referenz finden Sie im Bash Beginner's Guide , der folgende Informationen enthält:
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.
Um Klammer-Erweiterungsausdrücke zu analysieren, gehen wir von links nach rechts, erweitern jeden Ausdruck und bilden aufeinanderfolgende Produkte (in Bezug auf die Operation der Zeichenfolgenverkettung).
Betrachten wir nun Ihren ersten Ausdruck:
{{a..c},{1..3}}
In der Sprache des Bash Hacker-Wikis entspricht dies der ersten Form:
{string1,string2,...,stringN}
Wo N=2
, string1={a..c}
und string2={1..3}
- die Innen Klammer Expansionen durchgeführt werden , erste und jeder von ihnen in der Form zu sein {<START>..<END>}
. Alternativ können wir sagen, dass dies ein Klammererweiterungsausdruck ist, der nur aus einer Amble (keine Präambel oder Postamble) besteht. Das Amble ist eine durch Kommas getrennte Liste. Wir gehen die Liste also nacheinander durch und führen bei Bedarf zusätzliche Erweiterungen durch. Es wird kein Produkt gebildet, da keine benachbarten Ausdrücke vorhanden sind (das Komma wird als Trennzeichen verwendet).
Schauen wir uns als nächstes Ihren zweiten Ausdruck an:
{a..c},{1..3}
In der Sprache des Bash Hacker-Wikis entspricht dieser Ausdruck der Form:
{........}<POSTSCRIPT>
wobei das Nachskript der Unterausdruck ist ,{1..3}
. Alternativ können wir sagen, dass dieser Ausdruck ein amble ( {a..c}
) und ein postamble ( ,{1..3}
) hat. Das Amble wird zu der Liste erweitert a b c
und dann wird jedes von diesen mit jeder der Zeichenfolgen in der Erweiterung des Postamble verkettet. Die Postambel wird rekursiv verarbeitet: Sie hat eine Präambel von ,
und eine Amble von {1..3}
. Dies wird zur Liste erweitert ,1 ,2 ,3
. Die beiden Listen a b c
und ,1 ,2 ,3
werden dann zur Produktliste zusammengefasst a,1 a,2 a,3 b,1 b,2 b,3 c,1 c,2 c,3
.
Es könnte hilfreich sein, eine pseudoalgebraische Beschreibung zu geben, wie diese Ausdrücke analysiert werden, wobei Klammern "[]" Arrays bezeichnen, "+" Array-Verkettung und "*" das kartesische Produkt (in Bezug auf Verkettung).
So wird der erste Ausdruck erweitert (ein Schritt pro Zeile):
{{a..c},{1..3}}
{a..c} + {1..3}
[a b c] + [1 2 3]
a b c 1 2 3
Und so wird der zweite Ausdruck erweitert:
{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