Was ist der Unterschied zwischen "a [bc] d" (Klammern) und "a {b, c} d" (Klammern)?

28

Was ist der Unterschied zwischen a[bc]dund a{b,c}d? Warum nutzen Menschen, a{b,c}dwenn es sie schon gibt a[bc]d?

Weijun Zhou
quelle
Wer hat dir gesagt, dass du es benutzen sollst command a[bc]d?
Jesse_b
3
Es hat sicherlich seinen Nutzen, wenn man es richtig versteht.
Weijun Zhou
7
Ich verstehe einfach nicht, wie die Verwechslung zwischen den beiden passiert ist.
Jesse_b
Ich wurde ausdrücklich von einem weniger mit Linux vertrauten Kollegen dazu befragt, allerdings nicht in letzter Zeit.
Weijun Zhou
@Jesse_b Wenn Sie sie nur mit Operationen auf Dateien wie lsversuchen und Sie immer nur einzelne Zeichen versuchen, scheinen sie gleich zu funktionieren.
Nacht - Setzen Sie Monica

Antworten:

43

Die beiden sind sehr unterschiedlich.

a[bc]dist ein Dateinamenmuster (in anderen Shells als fish). Es wird auf die beiden Dateinamen erweitert abd und acdob dies die Namen der im aktuellen Verzeichnis vorhandenen Dateien sind.

  • Der [...]Teil ist ein Ausdruck in eckigen Klammern, der mit einem der aufgelisteten Zeichen übereinstimmt (oder Elemente sortiert, wenn Bereiche enthalten sind). Um das Muster abzugleichen, muss a[bc]ddas Zeichen zwischen den Zeichenfolgen aund din einem Dateinamen entweder a boder a sein c.

  • Wenn es abdexistiert, aber acdnicht, dann würde es nur expandieren abdund umgekehrt.

  • Wenn weder abd, noch acdvorhanden ist , in Abhängigkeit von der Schale und den Optionen, würde es einen Fehler (Original Unix auslösen sh, (t)csh, zsh, fish, bash -O failglob) und möglicherweise den Shell verlassen, oder lassen Sie das Muster unexpanded¹ (Bourne-like und rc-artigen Schalen) oder erweitern , um nichts ( bash/zsh/yash -o nullglobeinige ältere Versionen von fishOriginal-Unix shund (t)cshwenn es andere übereinstimmende Globs im selben Befehl gibt).

a{b,c}dist eine Klammererweiterung (in Schalen, die diese unterstützen). Es wird auf die beiden Saiten abd und erweitert acd.

  • Der {...}Teil ist eine durch Kommas getrennte Menge von Zeichenfolgen (in diesem Beispiel; in einigen Shell-Fällen kann es sich auch um einen Bereich wie a..koder 20..25oder einen fortgeschritteneren wie 00..20..2oder handeln 0..20..2%02d). Die Erweiterung wird berechnet, indem jede dieser Zeichenfolgen mit der Flanke kombiniert wird Streicher aund d. Diese Zeichenfolgen können länger als ein einzelnes Zeichen sein und können auch selbst Klammererweiterungen sein.

  • Die Erweiterung erfolgt unabhängig davon, ob diese Zeichenfolgen vorhandenen Dateinamen entsprechen oder nicht.

Wenn Sie Zeichenfolgen erstellen, verwenden Sie eine geschweifte Klammer. Wenn Sie mit Dateinamen übereinstimmen, verwenden Sie ein Dateinamenmuster.


¹ In diesem speziellen Fall kann es vorkommen, a[bc]ddass es sich um den Namen einer vorhandenen Datei handelt, weshalb es möglicherweise gefährlich ist, Dinge wie diese rm -f ./*.[ch]in Shells zu verwenden, und dies rm -f ./*.{c,h}ist weniger problematisch.

Kusalananda
quelle
Vielen Dank für die Klarstellung "Wenn abd existiert, aber acd nicht, dann würde es nur zu abd erweitern". Ich vermute, das fehlt in meiner Antwort.
Weijun Zhou
9
Ein weiterer entscheidender Unterschied besteht darin, dass a{b,c}ddie bund c-Teile keine einzelnen Buchstaben sein müssen. zB ex{ten,ci}sion. Wobei ex[tenci]sionoder was auch immer nur mit einem dieser Buchstaben übereinstimmt .
Alexis
7

a[bc]dist eine Mustererkennung und Teil des POSIX-Standards. In POSIX wird dies als "Musterklammerausdruck" eingeführt. Dies ist in Abschnitt 2.13 des Handbuchs dokumentiert

Ohne Anführungszeichen und außerhalb eines Klammerausdrucks haben die folgenden drei Zeichen in der Spezifikation von Mustern eine besondere Bedeutung:

    ?
      Ein Fragezeichen ist ein Muster, das mit einem beliebigen Zeichen übereinstimmt.
    *
      Ein Stern ist ein Muster, das mit mehreren Zeichen übereinstimmen soll, wie in Muster, die mit mehreren Zeichen übereinstimmen beschrieben.
    [
      Die offene Klammer soll einen Musterklammerausdruck einführen.

In Abschnitt 2.13.3 wird auch etwas erwähnt, das sich anders verhält als man es von regulären Ausdrücken erwartet, wenn es für die Dateinamenerweiterung verwendet wird (Hervorhebung von mir).

Die Regeln, die bisher in Muster, die mit einem einzelnen Zeichen übereinstimmen, und Muster, die mit mehreren Zeichen übereinstimmen, beschrieben wurden, werden durch die folgenden Regeln qualifiziert, die gelten, wenn die Mustervergleichsnotation für die Dateinamenerweiterung verwendet wird:

Das Schrägstrichzeichen in einem Pfadnamen muss explizit mit einem oder mehreren Schrägstrichen im Muster verglichen werden. Es darf weder mit einem Sternchen oder einem Fragezeichen als Sonderzeichen noch mit einem Klammerausdruck übereinstimmen. Schrägstriche im Muster sind vor Klammerausdrücken zu kennzeichnen. Daher kann ein Schrägstrich nicht in einem Musterklammerausdruck enthalten sein, der für die Dateinamenerweiterung verwendet wird. Wird ein Schrägstrich nach einem offenen eckigen Klammerzeichen gefunden, bevor eine entsprechende schließende eckige Klammer gefunden wird, wird die offene Klammer als gewöhnliches Zeichen behandelt. Beispielsweise "a[b/c]d"stimmt das Muster nicht mit solchen Pfadnamen wie abdoder überein a/d. Es stimmt nur mit einem Pfadnamen von wörtlich überein a[b/c]d.

a{b,c}dist eine Klammererweiterung , sie ist nicht in der Spezifikation von POSIX enthalten. Hier ist der entsprechende Teil aus dem Bash- Handbuch (Hervorhebung von mir):

Die Klammererweiterung ist ein Mechanismus, mit dem beliebige Zeichenfolgen generiert werden können. Dieser Mechanismus ähnelt der Dateinamenerweiterung (siehe Dateinamenerweiterung), die generierten Dateinamen müssen jedoch nicht vorhanden sein . Muster, die in geschweifte Klammern eingeschlossen werden sollen, haben die Form einer optionalen Präambel, gefolgt von einer Reihe von durch Kommas getrennten Zeichenfolgen oder einem Sequenzausdruck zwischen zwei geschweiften Klammern, gefolgt von einem optionalen Nachskript. Die Präambel wird jeder in geschweiften Klammern enthaltenen Zeichenfolge vorangestellt, und das Nachskript wird dann an jede resultierende Zeichenfolge angehängt und von links nach rechts erweitert.

Laut dem Kommentar von @mosvy ist dies zuerst von aufgetaucht, cshaber das Verhalten in bashunterscheidet sich von cshund von anderen Shells. Diese Art der Strebendehnung ist auch in vorhanden glob(3).

Es gibt eine andere Art der Klammererweiterung {a..z}, die erst nach bash3.0 erschien, und in bash4.0 wurden weitere hinzugefügt .

Führen Sie in einer Shell, in der das Globbing aktiviert ist, in einem leeren Ordner das folgende Ergebnis aus

$ echo a[bc]d
a[bc]d
$ echo a{b,c}d
abd acd

Wenn Sie sich in einer interaktiven Shell befinden und beide zutreffen, haben Sie als Antwort auf den Kommentar von @ Jesse_b a[bc]dweniger Probleme bei der Eingabe. Zum Beispiel grep pattern [ab][12].txt.

Weijun Zhou
quelle
2
Die Klammererweiterung ist kein "Bashismus"; es erschien zuerst in csh, lange bevor bash. Es ist auch in der Bibliotheksfunktion glob (3) enthalten. Der Unterschied besteht darin, dass bashes vor anderen Erweiterungen ausgeführt wird: Es a=A; ab=A/B; ac=A/C; echo $a{b,c}funktioniert in bash anders als in jeder anderen Shell.
Mosvy
Vielen Dank. Ich werde die Antwort aktualisieren.
Weijun Zhou