Was macht `. []. Foo []` in bash? Warum passt es zu ".."?

16

Schau dir folgendes an:

$ echo .[].aliases[]
..
$ echo .[].foo[]
..
$ echo .[].[]
..
$ echo .[].xyz[]
..
$ echo .xyz[].xyz[]
.xyz[].xyz[]
$ echo .xyz[].[]
.xyz[].[]

Anscheinend scheint das etwas zu beeinflussen, aber ich verstehe nicht, wie das Ergebnis zusammenkommt. Nach meinem Verständnis []handelt es sich um eine leere Zeichenklasse. Es wäre intuitiv, wenn

  • es stimmte nur mit der leeren Zeichenfolge überein; In diesem Fall würde ich erwarten, dass die Bash vollständig reproduziert wird, da in diesem Verzeichnis nichts mit ihr übereinstimmt, sondern auch Dinge wie ..aliases(im ersten Beispiel),
  • oder gar nichts; In diesem Fall würde ich erwarten, dass Bash die Zeichenfolge auch insgesamt reproduziert.

Dies ist mit GNU Bash, Version 4.4.23 (1) -Release.

Jonas Schäfer
quelle

Antworten:

25

Das [startet einen Satz. Ein Satz wird durch beendet ]. Aber es gibt eine Möglichkeit, ]als Teil der Menge, und das ]als erstes Zeichen anzugeben . Da eine leere Menge keinen Sinn ergibt, ist dies nicht mehrdeutig.

Ihre Beispiele sind also im Grunde genommen alle ein Punkt, gefolgt von einem Satz, der einen Punkt enthält. Daher entspricht er zwei Punkten.

Die späteren Beispiele finden keine Dateien und werden daher wörtlich zurückgegeben.

RalfFriedl
quelle
4

Nur Zeichenfolgen in Anführungszeichen unterliegen keiner Verschiebung:

$ echo ".[].aliases[]"
.[].aliases[]

Zeichenfolgen ohne Anführungszeichen können sich jedoch verschieben. Eine nicht in Anführungszeichen gesetzte Zeichenfolge, die ein *oder ein ?oder (gültig) [](Klammerausdruck) enthält, wird durch die Liste der Dateien geändert, die mit ihr übereinstimmen. So wie sich a *in alle Dateien im passenden Verzeichnis verwandelt und a ?Dateien mit nur einem Zeichen vergleicht, vergleicht a (gültig) []Dateien mit den Zeichen in Klammern. Ein Punkt ist ein gültiges Zeichen:

$ echo a[.]b
a[.]b

$ touch "a.b"
$ echo a[.]b
a.b

Um mit einem übereinstimmen zu können, muss ]es das erste Zeichen in den Klammern sein:

$ touch "a]b"
$ ls a[]]b
a]b

Ein leerer Klammerausdruck macht keinen Sinn (und ist nicht erweitert):

$ touch ab
$ ls a[]b
ls: cannot access 'a[]b': No such file or directory

Deshalb funktioniert das:

$ touch a]c abc afc azc a:c a?c aoc 
$ ls a[]bfz:?]c
abc  a:c  a?c  a]c  afc  azc

Denn [die Idee ist ähnlich:

$ touch a[c
$ ls a[[]c
a[c

Es kann sich jedoch an einer beliebigen Position in einem Klammerausdruck befinden:

$ ls a[]bf[z:?]c
abc  a:c  a?c  a[c  a]c  afc  azc

$ ls a[]bfz:?[]c
abc  a:c  a?c  a[c  a]c  afc  azc

Die von Ihnen eingegebene Zeichenfolge entspricht .[].foo[]einem Punkt, gefolgt von einem ], einem ., einem f, einem ooder einem [. Es ist ähnlich wie:

$ echo a[].foo[]c
a[c a]c afc aoc

Und es wird wie folgt passen:

$ touch .] .f .o .[ .a .b .z

$ echo .[].foo[]
.. .[ .] .f .o

Beachten Sie, dass der Verzeichniseintrag ..nicht erstellt werden muss, da er standardmäßig in jedem Verzeichnis vorhanden ist. Ein einfacher Punkt .wird jedoch nicht von einem Glob abgeglichen, da er explizit abgeglichen werden muss (indem tatsächlich ein Punkt verwendet wird).

Dies stimmt jedoch nicht überein, ..aliasesda der Klammerausdruck nur mit einem Zeichen übereinstimmt . Um mehrere Zeichen zu finden, müssen Sie ein *(beliebiges) verwenden:

$ touch ..a ..l ..i ..aliases ..alias ..ali
$ echo .[].aliases[]
.. .[ .] .a

$ echo .[].aliases[]*
.. .[ .] .a ..a ..ali ..alias ..aliases ..i ..l
Isaac
quelle