このスニペットを考えてみましょう:
stop () {
echo "${1}" 1>&2
exit 1
}
func () {
if false; then
echo "foo"
else
stop "something went wrong"
fi
}
通常、func
が呼び出されると、スクリプトが終了しますが、これは意図された動作です。ただし、次のようなサブシェルで実行された場合
result=`func`
スクリプトを終了しません。これは、呼び出しコードが関数の終了ステータスを毎回チェックする必要があることを意味します。これを回避する方法はありますか?これは何ですかset -e
は?
あなたcould元のシェルを殺す(kill $$
)exit
を呼び出す前に、おそらくそれでうまくいきます。だが:
代わりに、 Bash FAQの値を返すいくつかの方法 のいずれかを使用できます。それらのほとんどは残念ながらそれほど素晴らしいものではありません。関数を呼び出すたびにエラーのチェックでスタックするだけかもしれません( -e
には多くの問題があります )。それか、Perlに切り替えてください。
たとえば、終了ステータス77は、任意のレベルのサブシェルを終了することを意味し、
set -E
trap '[ "$?" -ne 77 ] || exit 77' ERR
(
echo here
(
echo there
(
exit 12 # not 77, exit only this subshell
)
echo ici
exit 77 # exit all subshells
)
echo not here
)
echo not here either
ERR
トラップと組み合わせたset -E
は、独自のエラー処理を定義できるという点で、set -e
の改良版と少し似ています。
Zshでは、ERRトラップは自動的に継承されるため、set -E
は必要ありません。TRAPERR()
関数としてトラップを定義し、$functions[TRAPERR]
のようにfunctions[TRAPERR]="echo was here; $functions[TRAPERR]"
を介してトラップを変更することもできます。
kill $$
の代わりに、kill 0
を試すこともできます。ネストされたサブシェルの場合に機能します(すべての呼び出し元とサイドプロセスがシグナルを受信します)…しかし、それでも残忍で醜いです。
(Bash固有の回答)Bashには例外の概念はありません。ただし、最も外側のレベルでset -o errexit(または同等の:set -e)を使用すると、コマンドが失敗すると、サブシェルがゼロ以外の終了ステータスで終了します。これが、サブシェルの実行に関する条件なしの入れ子になったサブシェルのセットである場合、スクリプト全体を効果的に「ロールアップ」して終了します。
さまざまなbashコードのビットを大きなスクリプトに含めようとする場合、これは注意が必要です。 bashの1つのチャンクは、それ自体で問題なく機能しますが、errexitの下で(またはerrexitなしで)実行されると、予期しない動作をします。
[192.168.13.16(f0f5e19e)〜22:58:22]#bash -o errexit /tmp/foo 問題が発生しました [192.168.13.16(f0f5e19e)〜22 :58:31]#bash /tmp/foo 問題が発生しました しかし、とにかくここに来ました [192.168.13.16(f0f5e19e)〜22:58:37]#猫/tmp/foo #!/bin/bash stop(){ echo "$ {1}" exit 1 } 偽の場合;次に、 echo "foo" else ( stop "something got bad" ) echo "But we here hereとにかく " fi [192.168.13.16(f0f5e19e)〜22:58:40]#
これを試して ...
stop () {
echo "${1}" 1>&2
exit 1
}
func () {
if $1; then
echo "foo"
else
stop "something went wrong"
fi
}
echo "Shell..."
func $1
echo "subshell..."
result=`func $1`
echo "Shell..."
echo "result=$result"
私が得る結果は...
# test_exitsubshell true
Shell...
foo
subshell...
Shell...
result=foo
# test_exitsubshell false
Shell...
something went wrong
ノート
if
テストがtrue
またはfalse
になるようにパラメーター化(2回の実行を参照)if
テストがfalse
の場合、サブシェルに到達することはありません。