関数があり、内部でpipefail
オプションを使用したいと思います。しかし、単純にset -o pipefail
を使用したくありません。スクリプトの別の部分がpipefail
の設定を期待しない可能性があるためです。もちろん、後でset +o pipefail
を実行することもできますが、pipefail
が関数の外部で設定されている場合、予期しない動作が発生する可能性もあります。
もちろん、pipefail
が設定されている場合、false | true
の終了コードをメジャーとして使用できますが、これは少し汚いようです。
設定されたbashオプションを確認するためのより一般的な(そしておそらく標準的な?)方法はありますか?
$SHELLOPTS
変数は、コロンで区切られたすべての設定オプションを保持します。例として、次のようになります。
braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
特定のオプションを確認するには、次のようにします。
# 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
bash-4.4
以上では、以下を使用できます。
myfunction() {
local -
set -o someoption
...
}
いくつかのメモ:
ash
からコピーされます。 ash
のアイデアは、$-
(オプションのセットを格納する)をローカルにすることです。 ash
で機能するのは、ash
ではlocal
は変数の値や属性に影響を与えないためです(bash
とは逆に、最初は変数を設定解除します) )。それでも、bash
と同じようにash
と同じように機能します。つまり、$-
を設定解除したり、デフォルトの動作に戻したりすることはありません。set -o option
で設定されたオプションではなく、shopt -s option
で設定されたオプションのみをカバーします(bash
は2つのオプションセットを持つ唯一のシェルです!)ローカル変数のように、それは静的ではなく動的スコープです。 $-
の値は、関数から戻るときに復元されますが、新しい設定は、関数によって呼び出される他の関数またはソーススクリプトに影響を与えます。静的スコープが必要な場合は、ksh93に切り替えて以下を使用する必要があります。
function myfunction {
set -o myoption
...
other_function
}
other_function
構文で宣言されている限り、function other_function {
は影響を受けません(Bourne other_function()...
構文ではない)。
オプションはリセットされないため、関数は他のコードによって設定されたオプションの影響を受ける可能性があります。これを回避するには、代わりにzsh
を使用します。 zsh
のlocal -
に相当するものはset -o localoptions
ですが、よく知られているエミュレーションモードを使用することもできます。ローカルに。例えば:
myfunction() {
emulate -L zsh
set -o someoption
...
}
正気なzsh-defaultオプションのセット(いくつかの例外はありますが、ドキュメントを参照)から始め、その上にオプションを追加します。これはash/bashのような動的スコープでもありますが、次のように他の関数を呼び出すこともできます。
emulate zsh -c 'other_function...'
そのother_function
をVanilla zshオプションを設定して呼び出すため。
zshには、最初からグローバルにオプションを変更しないようにすることができるいくつかの演算子もあります(_nullglob
/dotglob
の(N)
/(D)
glob修飾子、大文字と小文字を区別しないglobbingの(#i)
glob演算子など、${(s:x:)var}
$IFS
、${~var}
との混同を避けるために、パラメータ展開時にグロビングするrequest(他のBourne-ではnoglob
が必要)シェルのようにavoid(!)it)...
関数内でシェルオプションを設定したいが、呼び出し元に影響を与えたくない場合は、2つの異なる方法で行います。
関数をサブシェル内に置きます(中括弧の代わりに関数のステートメントを囲む括弧に注意してください):
function foo() (
set -o pipefail
echo inside foo
shopt -o pipefail
# ...
)
次に、呼び出し元はpipefailを設定解除でき、影響を受けません。
$ shopt -o pipefail
pipefail off
$ foo
inside foo
pipefail on
$ shopt -o pipefail
pipefail off
または
必要に応じてオプションをテストおよびリセットできます(関数ステートメントを囲む中括弧に注意してください-サブシェルはありません)。
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
cuonglm への帽子のヒント shopt -q
回答 。
以下は、bash
の-o
テストを使用して、pipefail
シェルオプションが設定されているかどうかをテストします(これは[[ ... ]]
で機能し、test
-inコマンド、ただし[ ... ]
は使用できません)。オプションが設定されていない場合は、オプションを設定し、関数が戻ったときに設定を解除するトラップをインストールします。
foo () {
if [[ ! -o pipefail ]]; then
set -o pipefail
trap 'set +o pipefail' RETURN
fi
# rest of function body
}
デバッグが含まれたコード:
foo () {
if [[ ! -o pipefail ]]; then
set -o pipefail
trap 'set +o pipefail' RETURN
fi
# rest of function body
if [[ -o pipefail ]]; then
echo 'pipefail is set (in function)'
else
echo 'pipefail is not set (in function)'
fi
}
if [[ -o pipefail ]]; then
echo 'pipefail is set'
else
echo 'pipefail is not set'
fi
foo
if [[ -o pipefail ]]; then
echo 'pipefail is set'
else
echo 'pipefail is not set'
fi
それを実行する:
$ bash script.sh
pipefail is not set
pipefail is set (in function)
pipefail is not set
$ bash -o pipefail script.sh
pipefail is set
pipefail is set (in function)
pipefail is set
RETURNトラップで指定されたコマンドは、シェル関数が戻った後に実行が再開する前に実行されます...
-p
オプション[to shopt]は、出力を入力として再利用できる形式で表示します。
foo() {
trap "$(shopt -p -o pipefail)" RETURN
set -o pipefail
echo inside foo
shopt -o pipefail
# ...
}
テスト
$ shopt -o pipefail
pipefail off
$ foo
inside foo
pipefail on
$ shopt -o pipefail
pipefail off
次の関数テンプレートは、set
オプションとshopt
オプションの両方が、関数が戻ったときに元の値に復元されるようにする一般的なケースを処理します。
foo() {
trap "$(shopt -p -o)$(shopt -p)" RETURN
# ...
}