だから私はいくつかのテストを実行するための小さなスクリプトを持っています。
javac *.Java && Java -ea Test
rm -f *.class
これの問題は、スクリプト./test
を実行すると、rm -f *.class
が成功したためにテストが失敗した場合でも、成功の終了コードを返すことです。
私がやりたいことを実現するために私が考えることができる唯一の方法は、私にとって醜く感じます。
javac *.Java && Java -ea Test
test_exit_code=$?
rm -f *.class
if [ "$test_exit_code" != 0 ] ; then false; fi
しかし、これは一般的な問題のようです-タスクを実行し、クリーンアップしてから、元のタスクの終了コードを返します。
これを行う最も慣用的な方法は何ですか(bashまたは単に一般的にシェルで)?
次のように、exit
コマンドとrm
コマンドをeval
を使用して単一の単純なコマンドにラップできます。
Java ... && Java ...
eval "rm -f *.class; exit $?"
このようにして、exit
に渡されたときの$?
の値は、eval
が実行される直前に割り当てられる値です。
私は一緒に行きます:
javac *.Java && Java -ea Test
test_exit_code=$?
rm -f *.class
exit "$test_exit_code"
exit
が利用可能なときにジャンプするのはなぜですか?
trap
を使用できます:
trap 'last_error_code=$?' ERR
例えば:
$ trap 'last_error_code=$?' ERR
$ false
$ echo $?
1
$ echo $last_error_code $?
1 0
私が知る限り、bashがよりCに似たプログラミング言語からのtry...finally
ブロックに最も近いもの(これがおそらく使用可能であれば必要なものです)はtrap
構造です。このように動作します:
trap "rm -f *.class" EXIT
javac *.Java && Java -ea Test
これにより、スクリプトの終了時に「rm -f * .class」が実行されます。もっと複雑なことがあれば、それを関数に入れることができます:
cleanup() {
...
}
trap cleanup EXIT
javac *.Java && Java -ea Test
もしそうしたいと思うなら、これをCのtry...catch...finally
ブロックのように機能するかなり一般的なイディオムに変えることができます。このようなもの:
(
trap "catch_block; exit" ERR
trap finally_block EXIT
# contents of try goes here
)
括弧はサブシェルを区切ることに注意してください。この構成では、スクリプト全体ではなく、コマンドが失敗した場合にサブシェルのみが終了します。サブシェルはいくぶん計算コストが高いので、サブシェルをあまり多く(数百)使用しないでください。スクリプトによっては、シェル関数とtrap ... RETURN
を使用して同じ効果をより効率的に達成できる場合がありますが、調査するのはあなた次第です。