
関数があり、その中でオプションを使用したいと考えています。しかし、スクリプトの別の部分では が設定されていない可能性があるので、pipefail
単純に にしたくありません。もちろん、後で を行うこともできますが、関数の外部で が設定された場合、予期しない動作が発生する可能性があります。set -o pipefail
pipefail
set +o pipefail
pipefail
もちろん、が設定されているfalse | true
場合は、 の終了コードを基準として使用することもできますpipefail
が、これは少し不潔なようです。
設定された bash オプションを確認するための、より一般的な (そしておそらく標準的な) 方法はありますか?
答え1
上記で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 }
構文 (Bourne 構文ではない)
other_function
を使用して宣言されている限り、 は影響を受けません。function other_function {
other_function()...
オプションをリセットしないので、関数は他のコードによって設定されたオプションの影響を受ける可能性があります。これを避けるには、
zsh
代わりに を使用します。zsh
の同等のものはlocal -
ですset -o localoptions
が、よく知られている を取得することもできます。エミュレーションモード地元で。 例えば:myfunction() { emulate -L zsh set -o someoption ... }
は、zsh のデフォルトのオプション セット (いくつかの例外があります。ドキュメントを参照してください) から開始し、その上にオプションを追加します。これは ash/bash のような動的スコープでもありますが、次のように他の関数を呼び出すこともできます。
emulate zsh -c 'other_function...'
これを
other_function
通常の zsh オプション セットで呼び出すためです。zshには、オプションをグローバルに変更することを避けるための演算子もいくつかあります(/の
(N)
/(D)
glob修飾子、大文字と小文字を区別しないグロブのための glob 演算子、との混在を避ける、など) 。nullglob
dotglob
(#i)
${(s:x:)var}
$IFS
${~var}
リクエストパラメータ展開時のグロブ(noglob
他のBourne系シェルでは避ける(!) それ)...
答え2
変数$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
答え3
関数内でシェル オプションを設定するが、呼び出し元に影響を与えたくない場合は、次の 2 つの方法があります。
オプション1: サブシェル
関数をサブシェル内に配置します (関数のステートメントを中括弧ではなく括弧で囲むことに注意してください)。
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
または
オプション2: テストとリセット
必要に応じてオプションをテストしてリセットできます (関数ステートメントを中括弧で囲んでいることに注意してください。サブシェルはありません)。
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
感謝しますクオングルム彼らのshopt -q
答え。
答え4
RETURNトラップを使用する
トラップで指定されたコマンドは、または
RETURN
で実行されたシェル関数またはシェル スクリプトが戻った後に実行が再開される前に実行されます。.
source
[...]
オプション-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 # ①
# ...
}
①はshopt -p -o
標準的な同等物に簡略化できますset +o
。