この参照マニュアルによると:
-E(また-o errtrace)
設定されている場合、ERRのトラップは、シェル関数、コマンド置換、およびサブシェル環境で実行されるコマンドによって継承されます。
ERRトラップは通常、このような場合には継承されません。
ただし、以下は機能しないため、誤って解釈している必要があります。
#!/usr/bin/env bash
# -*- bash -*-
set -e -o pipefail -o errtrace -o functrace
function boom {
echo "err status: $?"
exit $?
}
trap boom ERR
echo $( made up name )
echo " ! should not be reached ! "
私はすでに簡単な割り当てを知っています、 my_var =$(made_up_name)
、 set -e
を使用してスクリプトを終了します (つまり、errexit)。
-E / -o errtrace
です 上記のコードのように動作するはずですか?または、おそらく、私はそれを読み間違えましたか?
承認された回答:
注: zsh
ここでのほとんどの例で「インラインコメント」を受け入れるように構成せず、 sh <<-CMD <で行ったようにプロキシシェルを介して実行しないと、「悪いパターン」について文句を言います。 / code> 。
さて、上記のコメントで述べたように、bashのset -E
について具体的にはわかりません。 、しかし、POSIX互換シェルは、必要に応じて値をテストする簡単な手段を提供することを知っています:
sh -evx <<-CMD
_test() { echo $( ${empty:?error string} ) &&
echo "echo still works"
}
_test && echo "_test doesnt fail"
# END
CMD
sh: line 1: empty: error string
+ echo
+ echo 'echo still works'
echo still works
+ echo '_test doesnt fail'
_test doesnt fail
上記では、パラメータ拡張
を使用したことがわかります。 $ {empty?} _test()
をテストするには それでもreturn
s パス–最後の echo
で明らかなように これは、失敗した値が $(コマンド置換)
を強制終了するために発生します それを含むサブシェルですが、その親シェル– _test
現時点では–トラックを続けます。そしてecho
気にしない–改行だけを提供するのはとても幸せです。エコー
ない テスト。
しかし、これを考慮してください:
sh -evx <<-CMD
_test() { echo $( ${empty:?error string} ) &&
echo "echo still works" ; } 2<<-INIT
${empty?function doesnt run}
INIT
_test ||
echo "this doesnt even print"
# END
CMD
_test+ sh: line 1: empty: function doesnt run
_test()の
をフィードしたため INIT here-document
に事前評価されたパラメータを使用して入力する 現在、 _test()
関数はまったく実行を試みません。さらにsh
シェルは明らかにゴーストを完全に放棄し、エコー「これは印刷すらしません」
印刷すらしません。
おそらくそれはではありません 欲しいもの。
これは、 $ {var?}
が原因で発生します style parameter-expansionは、 shell
を終了するように設計されています パラメータが欠落している場合は、次のように機能します。
$ {parameter:?[word]}
Null
の場合はエラーを示します または未設定。
パラメータが設定されていないかnullの場合、単語の拡張
(または単語が省略されている場合は未設定であることを示すメッセージ)標準エラーに書き込まれる
シェルはゼロ以外の終了ステータスで終了します
。 それ以外の場合は、parameterの値が置き換えられます
。 インタラクティブシェルを終了する必要はありません。
ドキュメント全体をコピーして貼り付けることはしませんが、 set but null
で失敗したい場合 フォームを使用する値:
$ {var
😕エラーメッセージ}
:colon
を使用 上記のように。 null
が必要な場合 成功する値。コロンを省略してください。後で説明するように、これを無効にして、設定値に対してのみ失敗することもできます。
_test()の別の実行:
sh <<-CMD
_test() { echo $( ${empty:?error string} ) &&
echo "echo still works" ; } 2<<-INIT
${empty?function doesnt run}
INIT
echo "this runs" |
( _test ; echo "this doesnt" ) ||
echo "now it prints"
# END
CMD
this runs
sh: line 1: empty: function doesnt run
now it prints
これはあらゆる種類のクイックテストで機能しますが、上に _test()
が表示されます。 、パイプライン
の中央から実行します 失敗し、実際にはコマンドリスト
が含まれています 関数内のコマンドも次のecho
も実行されないため、サブシェルは完全に失敗します まったく実行しますが、 echo "now it prints"
であるため、簡単にテストできることも示されています。 印刷します。
悪魔は細部に宿っていると思います。上記の場合、終了するシェルはではありません スクリプトの_main |ロジック|パイプライン
しかし、 ($ {test?}が含まれるサブシェル)||
そのため、少しサンドボックス化が必要です。
そして、それは明白ではないかもしれませんが、反対の場合にのみ合格したい場合、または set =
のみに合格したい場合 値、それもかなり簡単です:
sh <<-CMD
N= #N is NULL
_test=$N #_test is also NULL and
v="something you would rather do without"
( #this subshell dies
echo "v is ${v+set}: and its value is ${v:+not NULL}"
echo "So this ${_test:-"$_test:="} will equal ${_test:="$v"}"
${_test:+${N:?so you test for it with a little nesting}}
echo "sure wish we could do some other things"
)
( #this subshell does some other things
unset v #to ensure it is definitely unset
echo "But here v is ${v-unset}: ${v:+you certainly wont see this}"
echo "So this ${_test:-"$_test:="} will equal NULL ${_test:="$v"}"
${_test:+${N:?is never substituted}}
echo "so now we can do some other things"
)
#and even though we set _test and unset v in the subshell
echo "_test is still ${_test:-"NULL"} and ${v:+"v is still $v"}"
# END
CMD
v is set: and its value is not NULL
So this $_test:= will equal something you would rather do without
sh: line 7: N: so you test for it with a little nesting
But here v is unset:
So this $_test:= will equal NULL
so now we can do some other things
_test is still NULL and v is still something you would rather do without
上記の例では、POSIXパラメーター置換の4つの形式すべてと、それらのさまざまな :colon null
を利用しています。 またはnot null
テスト。上記のリンクに詳細がありますが、ここに再びあります。
そして、 _test
を表示する必要があると思います 機能も機能しますよね? empty =something
を宣言するだけです 関数のパラメーターとして(または事前に):
sh <<-CMD
_test() { echo $( echo ${empty:?error string} ) &&
echo "echo still works" ; } 2<<-INIT
${empty?tested as a pass before function runs}
INIT
echo "this runs" >&2 |
( empty=not_empty _test ; echo "yay! I print now!" ) ||
echo "suspiciously quiet"
# END
CMD
this runs
not_empty
echo still works
yay! I print now!
この評価は独立していることに注意してください。失敗するために追加のテストは必要ありません。さらにいくつかの例:
sh <<-CMD
empty=
${empty?null, no colon, no failure}
unset empty
echo "${empty?this is stderr} this is not"
# END
CMD
sh: line 3: empty: this is stderr
sh <<-CMD
_input_fn() { set -- "[email protected]" #redundant
echo ${*?WHERES MY DATA?}
#echo is not necessary though
shift #sure hope we have more than $1 parameter
: ${*?WHERES MY DATA?} #: do nothing, gracefully
}
_input_fn heres some stuff
_input_fn one #here
# shell dies - third try doesnt run
_input_fn you there?
# END
CMD
heres some stuff
one
sh: line :5 *: WHERES MY DATA?
そして最後に、元の質問に戻ります。 $(コマンド置換)
でエラーを処理する方法 サブシェル? 真実は– 2つの方法がありますが、どちらも直接ではありません。問題の核心は、シェルの評価プロセス–シェル拡張( $(コマンド置換)
を含む)です。 )現在のシェルコマンドの実行よりもシェルの評価プロセスの早い段階で発生します。これは、エラーがキャッチされてトラップされる可能性がある場合です。
opが経験する問題は、現在のシェルがエラーを評価するまでに、<em> $(コマンド置換)
サブシェルはすでに置き換えられています–エラーは残っていません。
では、2つの方法は何ですか? $(コマンド置換)
内で明示的に実行するか サブシェルを使用しない場合と同じようにテストを使用するか、その結果を現在のシェル変数に吸収してその値をテストします。
方法1:
echo "$(madeup && echo : || echo '${fail:?die}')" |
. /dev/stdin
sh: command not found: madeup
/dev/stdin:1: fail: die
echo $?
126
方法2:
var="$(madeup)" ; echo "${var:?die} still not stderr"
sh: command not found: madeup
sh: var: die
echo $?
1
これは、1行あたりに宣言された変数の数に関係なく
失敗します:
v1="$(madeup)" v2="$(ls)" ; echo "${v1:?}" "${v2:?}"
sh: command not found: madeup
sh: v1: parameter not set
そして、戻り値は一定のままです:
echo $?
1
今すぐトラップ:
trap 'printf %s\n trap resurrects shell!' ERR
v1="$(madeup)" v2="$(printf %s\n shown after trap)"
echo "${v1:?#1 - still stderr}" "${v2:?invisible}"
sh: command not found: madeup
sh: v1: #1 - still stderr
trap
resurrects
shell!
shown
after
trap
echo $?
0