man bash
使用するには、次の文書を含めてくださいtrap
。
trap [-lp] [[arg] sigspec ...]
…
The ERR trap is not executed if the failed command is part of the command list
immediately following a while or until keyword, part of the test in an if statement,
part of a && or || list, or if the command's return value is being inverted via !.
These are the same conditions obeyed by the errexit option.
…
私は理解「&& または || の部分リスト」これは、コマンドがこれらの制御演算子を含むリストの一部である場合、終了状態がゼロでない場合でも同様です。ERR信号を送信しないでください。(または使用されている場合はスクリプトを終了しますset -o errexit
)。
しかし、ここに矛盾するように見えるテストスクリプトがあります。
#!/usr/bin/env bash
_trap_err() {
local status=$? sig=$1 line=$2;
echo "Exit status ${status} on line ${line}: \`${BASH_COMMAND}\`";
}
trap '_trap_err ERR $LINENO' ERR;
function control_operators() {
# The next line will send an ERR signal.
[[ 1 -eq 2 ]] && echo Hello;
}
control_operators;
# The next line will not send an ERR signal.
[[ 1 -eq 2 ]] && echo Hello;
echo Done;
出力は次のとおりです
❯ test.sh
Exit status 1 on line 14: `[[ 1 -eq 2 ]]`
Done
[[ 1 -eq 2 ]]
&& または || の一部として「熱くなっている」からです。ERR信号はトリガーしてはいけません。。
予想される出力は次のとおりです。
❯ test.sh
Done
また、ちょうどリスト[[ 1 -eq 2 ]] && echo Hello
~へこのcontrol_operators
関数は ERR 信号を送信しますが、[[ 1 -eq 2 ]] && echo Hello
外部この機能はそうではありません。
このスクリプト環境で設定されたオプションは次のとおりです(出力set -o | grep 'on$'
)。
braceexpand on
hashall on
interactive-comments on
xtrace on
質問:
- この動作は正常ですか、またはリストで制御演算子を誤って使用していますか(または文書を誤って解釈していますか?)。
- コマンドが条件式の一部であり、実際にエラー条件を構成していない場合、ERRトラップトリガを防ぐ最善の方法は何ですか?
|| true
1つのオプションは、各リストの最後に追加された制御演算子を使用することです。if [[ 1 -eq 2 ]]; then echo Hello; fi
別のオプションは代わりに略語を使用することです。これは(によると)「ifステートメントのテストの一部」なので、&&
ERR信号は送信されません。man bash
&& または ||" . リスト" いいえ。
[[ 1 -eq 2 ]]
ERR信号が関数内でのみ送信されるのはなぜですか?
修正する:@Kusalanandaの最初の答えは上記の例では正しいです(関数に追加するとERR信号がreturn 0
防止されます)。control_operators
ただし、以下は、「&&または||ルールを含むリストの一部」に違反しているように見える別の例です。
#!/usr/bin/env bash
_trap_err() {
local status=$? sig=$1 line=$2;
echo "Exit status ${status} on line ${line}: \`${BASH_COMMAND}\`";
}
trap '_trap_err ERR $LINENO' ERR;
true && false;
echo Done;
このスクリプトの出力は次のとおりです。
❯ test.sh
Exit status 1 on line 7: `false`
Done
このtrue && false
行は、コマンドがfalse
「&&または||リストの一部」であるため、ERR信号を送信しないでください。それでは、なぜこれを行うのですか?
アップデート2:私はbash 3.2を使ってmacOSで作業しています。これがまさにman bash
上記のスニペットで言及されていない理由です。「最後の&&または||を除くコマンド」。
答え1
ERR
呼び出しの戻り状態がゼロではないため、スクリプトはcontrol_operators
トラップをトリガーしています。関数テストはそうではありません。まっすぐ罠を発動させてください。
トラップ出力は、関数が呼び出された行になる行番号を印刷することによってこれを示します。
また、トラップ出力は、ゼロ以外の終了状態がどこから来るかを示し、これは関数テストの結果です。テストは関数で最後に実行されるため、関数の終了状態を設定します。
関数呼び出しが AND または OR リストの一部ではないため、トラップがトリガーされます。
更新された質問に対してERR
ゼロ以外の終了ステータスを返すコマンドが次の場合、トラップが引き続き呼び出されることを忘れました。最後リストの AND または OR コマンドです。
bash
マニュアルでは、私は以下を強調します。
ERR
失敗したコマンドが、while
またはuntil
キーワードの直後にあるコマンドのリストの一部、ステートメントのテスト部分、またはリストからif
実行されたコマンドの一部である場合、トラップは実行されません。&&
||
&&
最後または次のコマンドを除いて||
、最後のコマンドを除くパイプラインのすべてのコマンド、またはリバースコマンドの戻り値を使用する場合!
。
あなたの例は、ANDリストの最後true && false
なので、トラップをトリガーします。false
ERR
それを表現する別の方法は次のとおりですERR
。終了状態に決定リストまたはパイプに対してゼロ以外の終了状態を返します(!
またはこのコマンドで使用されている場合は0)。