Ich möchte fragen:
Warum wird echo {1,2,3}auf 1 2 3 erweitert, was ein erwartetes Verhalten ist, während echo [[:digit:]]zurückgegeben wird, [[:digit:]]während ich erwartet habe, dass alle Ziffern von 0bis gedruckt werden 9?
Ich möchte fragen:
Warum wird echo {1,2,3}auf 1 2 3 erweitert, was ein erwartetes Verhalten ist, während echo [[:digit:]]zurückgegeben wird, [[:digit:]]während ich erwartet habe, dass alle Ziffern von 0bis gedruckt werden 9?
Antworten:
Weil es zwei verschiedene Dinge sind. Dies {1,2,3}ist ein Beispiel für die Erweiterung der Zahnspange . Das {1,2,3}Konstrukt wird von der Shell erweitert , bevor es echoüberhaupt angezeigt wird. Sie können sehen, was passiert, wenn Sie Folgendes verwenden set -x:
$ set -x
$ echo {1,2,3}
+ echo 1 2 3
1 2 3
Wie Sie sehen können, wird der Befehl echo {1,2,3}erweitert auf:
echo 1 2 3
Ist [[:digit:]]jedoch eine POSIX-Zeichenklasse . Wenn Sie es geben echo, verarbeitet die Shell es auch zuerst, aber dieses Mal wird es als Shell-Glob verarbeitet . Es funktioniert genauso, als ob Sie ausführen, echo *wodurch alle Dateien im aktuellen Verzeichnis gedruckt werden. [[:digit:]]Ist aber ein Shell Glob, der mit jeder Ziffer übereinstimmt. Wenn ein Shell-Glob in Bash mit nichts übereinstimmt, wird er auf sich selbst erweitert:
$ echo /this*matches*no*files
+ echo '/this*matches*no*files'
/this*matches*no*files
Wenn der Globus mit etwas übereinstimmt, wird dieser gedruckt:
$ echo /e*c
+ echo /etc
/etc
In beiden Fällen wird echonur gedruckt, was die Shell zum Drucken auffordert. Im zweiten Fall wird jedoch angegeben, dass der Globus gedruckt werden soll, da der Glob mit etwas übereinstimmt ( /etc).
Da Sie also keine Dateien oder Verzeichnisse haben, deren Name aus genau einer Ziffer besteht (was [[:digit:]]übereinstimmen würde), wird der Glob auf sich selbst erweitert und Sie erhalten:
$ echo [[:digit:]]
[[:digit:]]
Versuchen Sie nun, eine Datei mit dem Namen zu erstellen 5und denselben Befehl auszuführen:
$ echo [[:digit:]]
5
Und wenn es mehr als eine übereinstimmende Datei gibt:
$ touch 1 5
$ echo [[:digit:]]
1 5
Dies ist (irgendwie) man bashin der Erläuterung der nullglobOptionen dokumentiert , die dieses Verhalten ausschalten:
nullglob
If set, bash allows patterns which match no files (see
Pathname Expansion above) to expand to a null string,
rather than themselves.
Wenn Sie diese Option einstellen:
$ rm 1 5
$ shopt -s nullglob
$ echo [[:digit:]] ## prints nothing
$
shopt -s failglob, um ein nützlicheres Verhalten zu erhalten, das dem von modernen Muscheln wie zshoder ähnelt fish.
failglob. nullglobkann zu unerwarteten Problemen führen, z. B. beim Einfügen einer URL mit einer ?.
nullglob, um zu demonstrieren, dass das Muster von der Shell als Glob interpretiert wird.
{1,2,3}ist Klammernerweiterung , dehnt es sich auf die Worte , ohne Rücksicht aufgeführt ihre Bedeutung.
[...]ist eine Zeichengruppe, die in der Dateinamenerweiterung (oder im Platzhalter oder Glob) ähnlich wie das Sternchen *und das Fragezeichen verwendet wird ?. Es entspricht jedem einzelnen darin aufgelisteten Zeichen oder Zeichen, die Mitglieder benannter Gruppen sind, z. B. [:digit:]wenn diese aufgelistet sind. Das Standardverhalten der meisten Shells besteht darin, den Platzhalter unverändert zu lassen, wenn keine passenden Dateien vorhanden sind.
(Beachten Sie, dass Sie einen Platzhalter / ein Muster nicht wirklich in eine Reihe von Zeichenfolgen umwandeln können, mit denen es übereinstimmen würde. Das Sternchen kann mit einer beliebigen Zeichenfolge beliebiger Länge übereinstimmen. Wenn Sie also ein beliebiges Muster erweitern, das es enthält, wird eine unendliche Liste von Zeichenfolgen erstellt.)
So:
$ bash -c 'echo [[:digit:]]' # bash leaves it as-is
[[:digit:]]
$ zsh -c 'echo [[:digit:]]' # zsh by default complains if no match
zsh:1: no matches found: [[:digit:]]
$ touch 1 3 d i g t
$ bash -c 'echo [[:digit:]]' # now there are two matches
1 3 # note that d, i, g and t do NOT match
Aber dennoch:
$ bash -c 'echo {1,2,3}'
1 2 3
Beide werden durch die Shell erweitert . Es spielt keine Rolle, ob der von Ihnen ausgeführte Befehl lsoder echooder ist rm. Beachten Sie auch, dass wenn eines dieser Elemente zitiert wird, es nicht erweitert wird:
$ bash -c 'echo "[[:digit:]]"' # even though matching files still exist
[[:digit:]]
$ bash -c 'echo "{1,2,3}"'
{1,2,3}
[[:digit:]] vor dem Weitergeben an echo, echosieht also nie [[:digit:]], sie sieht nur 1 3. Sie können dies in Aktion sehen, indem Sie set -xausführen, wodurch die tatsächlich ausgeführten Befehle gedruckt werden (ausführen set +x, um sie wieder auszuschalten).
echosucht nicht nach Dateien, die Shell tut dies, bevor das ausgeführt wird echo.
{1,2,3}(und zB {1..3}sind Verstrebung Expansionen . Sie werden von der Schale , bevor die Befehlsausführung interpretiert.
[[:digit:]]ist ein Mustervergleichstoken , aber Sie verwenden es nicht an einem Speicherort mit Dateien, die diesem Muster entsprechen. Wenn Sie eine Musterübereinstimmung verwenden, die keine Übereinstimmungen aufweist, wird sie auf sich selbst erweitert:
$ echo [[:digit:]]; touch 3; echo [[:digit:]]
[[:digit:]]
3