Festlegen von Bash-Optionen in einem zusammengesetzten Befehl

Festlegen von Bash-Optionen in einem zusammengesetzten Befehl

Ich habe festgestellt, dass das Setzen der extglobShell-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 shoptist 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 extglobwird die Sprachsyntax geändert, indem neue Mustervergleichsoperatoren hinzugefügt werden, die während der Tokenisierung erkannt werden.

Da der shoptBefehl 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 timeeine 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 ifabgeschlossen ist.

verwandte Informationen