
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, pipefail
dass dies festgelegt wird. Natürlich könnte ich dies set +o pipefail
nachträglich tun, aber falls pipefail
dies außerhalb meiner Funktion festgelegt wird, kann dies ebenfalls zu unerwartetem Verhalten führen.
Natürlich könnte ich false | true
als Maßstab den Exit-Code von verwenden, wenn dieser pipefail
gesetzt 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.4
und 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) lokalash
zu 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.$-
ash
ash
local
bash
bash
ash
$-
- es deckt nur die mit festgelegten Optionen ab
set -o option
, nicht die von festgelegtenshopt -s option
(bash
da 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_function
ist nicht betroffen, solange esfunction 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
zsh
stattdessen verwenden.zsh
ist das Äquivalent vonlocal -
isset -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_function
mit 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ürnullglob
/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 (noglob
in anderen Bourne-ähnlichen Shells muss manvermeiden(!) Es)...
Antwort2
Die $SHELLOPTS
Variable 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 -q
Antwort.
Antwort4
Verwenden Sie eine RETURN-Falle
Mit einem Trap angegebene Befehle
RETURN
werden ausgeführt, bevor die Ausführung fortgesetzt wird, nachdem eine Shell-Funktion oder ein mit ausgeführtes Shell-Skript.
odersource
zurückgegeben wurde.[…]
Die-p
Option [to shopt] bewirkt, dass die Ausgabe in einer Form angezeigt wird, die als Eingabe wiederverwendet werden kann.
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 set
als auch shopt
die Optionen auf ihre ursprünglichen Werte zurückgesetzt werden, wenn eine Funktion zurückkehrt:
foo() {
trap "$(shopt -p -o; shopt -p)" RETURN # ①
# ...
}
① shopt -p -o
kann auf das Standardäquivalent vereinfacht werden set +o
.