私は主に起動/停止/状態で動作する段階的なタスクで構成されたスクリプトを持っています。
私が経験している問題は、起動時にすべての操作が失敗する可能性があり、安全なロールバックのために停止操作を使用する必要があることです。
Bashでどうすればいいですか?
私は次のことを考えています(動作しません)。
operation1_start() {}
operation2_start() {}
operation1_stop() {}
operation2_stop() {}
operation1_start && rollback=operation1_stop;$rollback
test_validity || $($rollback)
operation2_start && rollback=operation2_stop;$rollback
test_validity || $($rollback)
答え1
次の2つのシェルプログラミング技術が役に立ちます。
- 走れば
set -e
、コマンドがゼロ以外の状態を返すと(if
またはwhile
条件などの明白なものがない限り)、シェルはすぐに終了します。 - 走れば
trap 'somecode' EXIT
スクリプトが終了すると(明示的または暗黙的な終了のためset -e
)、somecode
最初に実行されます。エントリには、somecode
最後$?
のコマンドのステータスが含まれます。
したがって、次のように書くことができます。
(set -e; trap 'abort operation a' EXIT; perform operation a; )
ERR
Bashでは、代わりにトラップを設定できますEXIT
。set -e
これらのトラップは、シェルがシャットダウンしたときにのみ実行されます。さらに、ERR
トラップは関数に対してローカルです。
set -e
operation_a () {
trap 'abort code' ERR
perform operation a
}
可能であれば、ドラフトを最初に作成して実行する方が簡単です。原子取引を提出するための措置です。たとえば、ファイルに書き込む場合は、ターゲットディレクトリの一時ファイルに書き込み、新しいファイルを所定の位置に移動するをmv
呼び出します。これはkill -9
、停電のためにスクリプトが終了するとロールバックが実行されないため、ロールバックコードの形式でクリーンアップが必要なものよりはるかに強力です。
答え2
実際に配列を使用してこれを達成しました。うまくいくようです(私はロールバックであることを関数に知らせるために追加のパラメータも追加しました)。
abc()
{
echo "abc----$1";
}
cda()
{
echo "cda----$1";
}
safe_rollback=( )
add_rollback()
{
safe_rollback[${#safe_rollback[*]}]=$1;
}
run_rollback()
{
while [ ${#safe_rollback[@]} -ge 1 ]; do
${safe_rollback[${#safe_rollback[@]}-1]} rollback;
unset safe_rollback[${#safe_rollback[@]}-1];
done
}
add_rollback cda
add_rollback abc
run_rollback
答え3
実際に行うことは、さまざまなシナリオに基づいて、起動/ステータス/続行/ロールバック/停止タイプのタスクを実行できるビルドプロセスの複製のように聞こえます。シェルスクリプトでMakefileを使用すると、状態を決定する相互依存関係をよりエレガントに定義できるため、この効果をよりエレガントに得ることができます。