シェルスクリプトのエラークリーンアップロジックを含む最良の方法は何ですか?
具体的には、以下を実行するスクリプトがあります。
mount a x
mount b y
setup_thing
mount c z
do_something
umount z
cleanup_thing
umount y
umount x
すべてのマウントとdo_something
それ自体が失敗する可能性があります。たとえば、mount c z
インストールが失敗した場合は、終了する前に正常にインストールされたインストールを削除するスクリプトが必要です。
クリーンアップコードを何度も繰り返したくないし、すべてをif-nestでラップしたくありません(マウントを追加すると、すべてを再インデントする必要があるためです)。
上記の内容を次のように作成できるように最終スタックなどを生成する方法はありますか?
set -e
mount a x && finally umount x
mount b y && finally umount y
setup_thing && finally cleanup_thing
mount c z && finally umount z
do_something
"finally"コマンドが登録されると、終了、通過、または失敗時に(逆順)実行されます。ただし、正常に設定されていないものはクリーンアップされません(インストールが失敗するとクリーンアップが安全ではない可能性があるため)。実行)。
つまり、すべてが成功すれば、、、、umount z
-失敗だけする場合でも同様の順序で実行されます。ただし、失敗した場合にのみ実行されます。cleanup_thing
umount y
umount x
do_something
mount b y
umount x
(失敗した場合は正確な終了コードを維持する必要はありませんが、ゼロまたはゼロ以外の値で適切に終了する必要があるかどうかです。)
終了時にコマンドを実行できる組み込み機能があることはわかっていますが、trap
これは1つのコマンドのみをサポートし、毎回それを置き換えます。これを上記のようなスタックに拡張する方法はありますか?それともこれを行う他のきれいな方法はありますか?
Ye Olde Cコードのエラー処理パターンでも同様の結果が得られますが、x || goto cleanup_before_x
もちろんgotoはありません。
理想的には(da)shで動作しますが、単純化されている場合はbashも要求できます。 (たぶん配列を使用していますか?)
ベストアンサー1
trap
一般的な手法は、操作が完了したらすべての項目を元に戻すことです。等級でなければなりません。つまり、一部の手順を完了できない場合は、正常に失敗する必要があります。
#!/bin/bash
clean_up=false
errorhandler () {
umount z || true
$clean_up && cleanup_thing
umount y || true
umount x
}
trap errorhandler ERR EXIT
mount a x
mount b y
setup_thing
clean_up=true
mount c z
do_something
トラップもトリガーされるため、EXIT
スクリプトが正常に終了する前にも実行されるため、明示的にクリーンアップする必要はありません。
私は偽のERR
信号がBash拡張だと思います。したがって、これはAsh / Dash / Legacy Bourneシェルなどでは機能しません。