Nun, es wird eine Schicht nach der anderen entwirrt:
X{{a..c},{1..3}}Y
wird dokumentiert als erweitert zu X{a..c}Y
X{1..3}Y
(das ist X{A,B}Y
erweitert XA
XB
mit A
Sein {a..c}
und B
Sein {1..3}
), selbst dokumentiert als erweitert zu XaY
XbY
XcY
X1Y
X2Y
X3Y
.
Was Dokumentieren wert sein kann , ist , dass sie ineinander verschachtelt werden können (dass die ersten }
nicht nahe dem ersten {
in zum Beispiel dort).
Ich nehme an, dass Muscheln sich dafür entschieden haben, die inneren Klammern zuerst zu lösen , indem sie nacheinander auf jedes Schließen einwirken }
:
X{{a..c},{1..3}}
X{a,{1..3}}Y
X{b,{1..3}}Y
X{c,{1..3}}Y
(das wird A{a..c}B
erweitert AaB
AbB
AcB
, wo A
ist X{
und B
ist ,{1..3}Y
)
X{a,1}Y
X{a,2}Y
X{a,3}Y
X{b,1}Y
X{b,2}Y
X{b,3}Y
X{c,1}Y
X{c,2}Y
X{c,3}Y
XaY
X1Y
XaY
Xa2
...
Aber ich finde das nicht besonders intuitiv oder nützlich (siehe Kevins Beispiel in Kommentaren), es würde immer noch eine gewisse Unklarheit darüber geben, in welcher Reihenfolge die Erweiterungen durchgeführt würden, und so ist es nicht csh
(die Shell, die die Klammer einführte) Erweiterung in den späten 70er Jahren, während die {1..3}
Form später (1995) von zsh
und {a..c}
später (2004) von kam bash
) es tat.
Beachten Sie, dass csh
(von Anfang an, siehe die Manpage zu 2BSD (1979) ) die Tatsache dokumentiert hat, dass geschachtelte Klammererweiterungen geschachtelt werden können, ohne explizit anzugeben, wie geschachtelte Klammererweiterungen erweitert werden sollen. Sie können sich aber den csh
Code von 1979 ansehen, um zu sehen, wie es damals gemacht wurde. Sehen Sie, wie es das Verschachteln tatsächlich explizit handhabt und wie es von den äußeren Klammern aus gelöst wird.
Ich sehe jedenfalls nicht wirklich ein, wie sich die Expansion von {a..c},{1..3}
auswirken könnte. In diesem Fall ist der ,
Operator kein Operator für eine geschweifte Klammer (da er sich nicht in geschweiften Klammern befindet) und wird daher wie ein normales Zeichen behandelt.
/dev/{h,s}d{a..d}{1..4,}
. Nehmen wir nun an, Sie möchten es erweitern, um auch/dev/null
und einzuschließen/dev/zero
. Wenn die Klammererweiterung von innen nach außen funktioniert, wäre die Konstruktion dieser Erweiterung wirklich ärgerlich. Aber weil es von außen nach innen funktioniert, ist es ziemlich trivial:/dev/{null,zero,{h,s}d{a..d}{1..4,}}
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:
zum Ergebnis dieses Ausdrucks:
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:
Das Format eines Klammer-Erweiterungs-Tokens lautet also wie folgt:
Der Haupteinstiegspunkt für die Erweiterung ist eine Funktion,
brace_expand
die wie folgt beschrieben wird: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: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
diebrace_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:
Und das Parsen wird wie folgt beschrieben:
Eine weitere Referenz finden Sie im Bash Beginner's Guide , der folgende Informationen enthält:
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:
In der Sprache des Bash Hacker-Wikis entspricht dies der ersten Form:
Wo
N=2
,string1={a..c}
undstring2={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:
In der Sprache des Bash Hacker-Wikis entspricht dieser Ausdruck der Form:
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 erweiterta 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 Listena b c
und,1 ,2 ,3
werden dann zur Produktliste zusammengefassta,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):
Und so wird der zweite Ausdruck erweitert:
quelle
Mein Verständnis ist das:
Die inneren Klammern werden zuerst (wie immer) gelöst, was sich dreht
in
Da sich das
,
in geschweiften Klammern befindet, werden nur geschweifte Elemente voneinander getrennt.Aber im Fall von
Das
,
ist nicht in geschweiften Klammern, dh es ist ein gewöhnliches Zeichen, das auf beiden Seiten Klammernpermutationen verursacht.quelle
{a..c}
entweder aufa,b,c
odera b c
je nach Luftfeuchtigkeit und Dow Jones auflösen? Ordentlich.{{a..c},{1..3}}
es dasselbe ist wie{a,b,c,1,2,3}
, dann sollte es nicht{{a..c}.{1..3}}
dasselbe sein wie{a,b,c.1,2,3}
? Das ist natürlich nicht der Fall.,
ist die geschweifte Klammer Expansion Trennzeichen,.
nicht. Warum sollte ein gewöhnlicher Charakter zu denselben Ergebnissen führen wie ein besonderer?c.1
ist ein Klammerelement. Aber in{a..c}.{1..3}
der.
ist der Anker für die Klammererweiterungen links und rechts. Bei,
den äußeren Klammern handelt es sich um die Klammererweiterung, da deren Inhalt das Klammererweiterungsformat hat, bei den anderen.
nicht, weil deren Inhalt das Format nicht hat.{{a..c},{1..3}}
verwandelt sich in{a,b,c,1,2,3}
dann einige Kommas zwischen gerade erschienena
,b
undc
. Warum würden sie nicht auf die gleiche Weise mit erscheinen{a..c}.{1..3}
? Der Kommentar von @kubanczyk handelt von der gleichen Sache, wenn die Kommas dort so erscheinen, woher wissen wir, wann die Erweiterung Kommas erzeugt und wann nicht? Die Antwort ist natürlich, dass es niemals selbst Kommas erzeugt, sondern eine Liste von Wörtern. Also wird nichts in{a,b,c,1,2,3}
oder verwandelt{a,b,c.1,2,3}
.