Ich habe festgestellt, dass das Setzen der extglob
Shell-Option nur innerhalb eines zusammengesetzten Befehls zum Fehlschlagen nachfolgender erweiterter Globs führt. Müssen Shell-Optionen außerhalb zusammengesetzter Befehle gesetzt werden? Ich habe in den Manpages von Bash keinen Hinweis auf eine solche Anforderung gesehen.
Beispielsweise funktioniert das folgende Skript einwandfrei (druckt a.0 a.1
):
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
shopt -s extglob
ls "a."!(b*)
Wenn die letzten beiden Zeilen jedoch als zusammengesetzter Befehl ausgeführt werden, schlägt das Skript mit dem folgenden Fehler fehl:
syntax error near unexpected token `('
` ls "a."!(b*)'
Getestet wurde dies mit Bash-Versionen von 4.2 bis 4.4 und mit einer Vielzahl vonzusammengesetzte Befehle:
(1) Bedingung --if
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
if true; then
shopt -s extglob
ls "a."!(b*)
fi
(2) Hosenträger --{ }
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
{
shopt -s extglob
ls "a."!(b*)
}
(3) Unterschale -- ( )
:
#!/bin/bash
touch a.0 a.1 \
a.b.0 a.b.1
(
shopt -s extglob
ls "a."!(b*)
)
In allen Fällen shopt
ist das Skript erfolgreich, wenn es außerhalb des zusammengesetzten Befehls verschoben wird.
Antwort1
Kein Teil eines zusammengesetzten Befehls wird ausgeführt, bevor der gesamte Befehl analysiert wurde, was indirekt imShell-BetriebAbschnitt des Handbuchs: Die gesamte Tokenisierung und Analyse erfolgt, bevor „der“ Befehl ausgeführt wird. Durch die Aktivierung extglob
wird die Sprachsyntax geändert, indem neue Mustervergleichsoperatoren hinzugefügt werden, die während der Tokenisierung erkannt werden.
Da der shopt
Befehl zum !(
Erreichen von noch nicht ausgeführt wurde, wird er entweder als versuchter Verlaufserweiterungsvorgang ( !
) oder als Steueroperator betrachtet (
und nicht !(
als einzelnes Element (dasselbe gilt für @(
usw., außer dass dort keine Verlaufserweiterung vorhanden ist).
Wenn die Analyse dieses Token erreicht, tritt in beiden Fällen im Allgemeinen ein Fehler auf, auch wenn !(...)
am Anfang einer Zeile oder danach time
eine negierte Subshell-Pipeline steht. „ unexpected token `('
“ bedeutet, dass an dieser Stelle kein Subshell-Ausdruck akzeptiert werden konnte.
Dies ist etwas ärgerlich, wenn Sie Extglob nur vorübergehend in einer Subshell aktivieren möchten. Eine Problemumgehung besteht darin, eine Funktion zu definieren, die den gewünschten Glob verwendet, dann Extglob wieder zu deaktivieren undDannRufen Sie die Funktion aus der Subshell mit aktiviertem Extglob auf:
shopt -s extglob
f() { ls "a."!(b*) ; }
shopt -u extglob
(
shopt -s extglob
f
)
Es ist sehr klobig.
Derselbe Effekt tritt ein, wenn Sie einen Alias innerhalb eines zusammengesetzten Befehls erstellen, da diese ebenfalls vor der Analyse verarbeitet werden:
if true
then
alias foo=echo
foo bar
fi
foo xyz
wird gedruckt foo: command not found
, und dann xyz
, weil der AliasIsterstellt, aber erst verfügbar, wenn dies if
abgeschlossen ist.