Verwenden Sie eine RETURN-Falle

Verwenden Sie eine RETURN-Falle

Ich habe eine Funktion und möchte die Option darin verwenden pipefail. Ich möchte dies aber nicht einfach tun set -o pipefail, da ich befürchte, dass ein anderer Teil des Skripts nicht erwartet, pipefaildass dies festgelegt wird. Natürlich könnte ich dies set +o pipefailnachträglich tun, aber falls pipefaildies außerhalb meiner Funktion festgelegt wird, kann dies ebenfalls zu unerwartetem Verhalten führen.

Natürlich könnte ich false | trueals Maßstab den Exit-Code von verwenden, wenn dieser pipefailgesetzt ist, aber das wirkt ein wenig unsauber.

Gibt es eine allgemeinere (und vielleicht kanonischere?) Möglichkeit, die festgelegten Bash-Optionen zu überprüfen?

Antwort1

Ab bash-4.4und darüber können Sie Folgendes verwenden:

myfunction() {
  local -
  set -o someoption
  ...
}

Einige Anmerkungen:

  • das wurde von kopiert ash. In besteht die Idee darin , (das den Satz von Optionen speichert) lokal ashzu machen . Es funktioniert in , weil in weder den Wert noch die Attribute der Variable beeinflusst werden (im Gegensatz zu dem Fall, in dem es sie zunächst aufhebt). Dennoch funktioniert es auch mit auf die gleiche Weise wie in als Sonderfall, d. h. es führt nicht dazu, dass es aufgehoben wird oder zu einem Standardverhalten zurückkehrt.$-ashashlocalbashbashash$-
  • es deckt nur die mit festgelegten Optionen ab set -o option, nicht die von festgelegten shopt -s option( bashda es die einzige Shell mit zwei Optionssätzen ist!)
  • Wie bei lokalen Variablen handelt es sich um eine dynamische Bereichszuordnung, nicht um eine statische. Der Wert $-wird bei der Rückkehr von der Funktion wiederhergestellt, aber die neue Einstellung wirkt sich auf die anderen Funktionen oder Quellskripte aus, die von Ihrer Funktion aufgerufen werden. Wenn Sie eine statische Bereichszuordnung wünschen, müssen Sie zu ksh93 wechseln und Folgendes verwenden:

    function myfunction {
      set -o myoption
      ...
      other_function
    }
    

    Davon other_functionist nicht betroffen, solange es function other_function {auch mit der Syntax deklariert wird (und nicht mit der Bourne- other_function()...Syntax).

  • Da die Optionen nicht zurückgesetzt werden, kann Ihre Funktion immer noch von Optionen beeinflusst werden, die von anderem Code gesetzt wurden. Um das zu vermeiden, sollten Sie zshstattdessen verwenden. zshist das Äquivalent von local -is set -o localoptions, aber Sie können auch zu einem bekanntenEmulationModusörtlich. Zum Beispiel:

    myfunction() {
      emulate -L zsh
      set -o someoption
      ...
    }
    

    würde mit einem vernünftigen zsh-Standardsatz von Optionen beginnen (mit einigen Ausnahmen, siehe Dokumentation), zu dem Sie Ihre Option hinzufügen. Das ist auch dynamische Bereichsbestimmung wie in Ash/Bash, aber Sie können auch andere Funktionen aufrufen mit:

    emulate zsh -c 'other_function...'
    

    damit dies other_functionmit einem Standard-Zsh-Optionssatz aufgerufen werden kann.

    zsh hat auch eine Reihe von Operatoren, die Sie davon abhalten können, Optionen global zu ändern (wie (N)/ (D)Glob-Qualifizierer für nullglob/ dotglob, (#i)Glob-Operator für Groß- und Kleinschreibung ignorierendes Globbing, ${(s:x:)var}um eine Vermischung mit zu vermeiden $IFS, ${~var}umAnfrageGlobbing bei der Parametererweiterung ( noglobin anderen Bourne-ähnlichen Shells muss manvermeiden(!) Es)...

Antwort2

Die $SHELLOPTSVariable enthält alle gesetzten Optionen, getrennt durch Doppelpunkte. Sie könnte beispielsweise so aussehen:

braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor

Um eine bestimmte Option zu überprüfen, können Sie Folgendes tun:

# check if pipefail is set, if not set it and remember this
if [[ ! "$SHELLOPTS" =~ "pipefail" ]]; then
    set -o pipefail;
    PIPEFAIL=0;
else
    PIPEFAIL=1;
fi

# do something here

# reset pipefail, if it was not set before
if [ "$PIPEFAIL" -eq 0 ]; then
    set +o pipefail;
fi

Antwort3

Wenn Sie eine Shell-Option innerhalb einer Funktion festlegen möchten, den Aufrufer jedoch nicht beeinflussen möchten, haben Sie zwei verschiedene Möglichkeiten:

Option 1: Unterschale

Platzieren Sie die Funktion in einer Untershell (beachten Sie die Klammern, die die Anweisungen der Funktion umgeben, anstelle der geschweiften Klammern):

function foo() (
  set -o pipefail
  echo inside foo
  shopt -o pipefail
  # ...
)

Anschließend kann der Anrufer Pipefail deaktivieren und ist davon nicht betroffen:

$ shopt -o pipefail
pipefail        off
$ foo
inside foo
pipefail        on
$ shopt -o pipefail
pipefail        off

oder

Option 2: Testen und Zurücksetzen

Sie können die Option nach Bedarf testen und zurücksetzen (beachten Sie die geschweiften Klammern um die Funktionsanweisungen – keine Subshell):

function foo() {
  shopt -q -o pipefail
  local resetpipefail=$?
  set -o pipefail
  echo inside foo
  shopt -o pipefail
  # ...
  # only reset pipefail if needed
  [[ $resetpipefail -eq 1 ]] && set +o pipefail  
}

$ shopt -o pipefail
pipefail        off
$ foo
inside foo
pipefail        on
$ shopt -o pipefail
pipefail        off

Hut ab vorAbonnierenfür ihreshopt -qAntwort.

Antwort4

Verwenden Sie eine RETURN-Falle

Mit einem Trap angegebene Befehle RETURNwerden ausgeführt, bevor die Ausführung fortgesetzt wird, nachdem eine Shell-Funktion oder ein mit ausgeführtes Shell-Skript .oder sourcezurückgegeben wurde.

[…]
Die -pOption [to shopt] bewirkt, dass die Ausgabe in einer Form angezeigt wird, die als Eingabe wiederverwendet werden kann.

https://www.gnu.org/software/bash/manual/bash.html

foo() {
  trap "$(shopt -p -o pipefail)" RETURN
  set -o pipefail
  echo inside foo
  shopt -o pipefail
  # ...
}

Prüfen

$ shopt -o pipefail
pipefail        off
$ foo
inside foo
pipefail        on
$ shopt -o pipefail
pipefail        off

Die folgende Funktionsvorlage behandelt den allgemeinen Fall, sicherzustellen, dass sowohl die Optionen setals auch shoptdie Optionen auf ihre ursprünglichen Werte zurückgesetzt werden, wenn eine Funktion zurückkehrt:

foo() {
  trap "$(shopt -p -o; shopt -p)" RETURN # ①
  # ...
}

shopt -p -okann auf das Standardäquivalent vereinfacht werden set +o.

verwandte Informationen