java trycatchのようなLinuxbashコマンドはありますか?それとも、Linuxシェルは常に継続しますか?
try {
`executeCommandWhichCanFail`
mv output
} catch {
mv log
} finally {
rm tmp
}
あなたの例に基づくと、スクリプトがどのように終了するかに関係なく、常に一時ファイルを削除するのと同じようなことをしようとしているように見えます。Bashでこれを行うには、trap
組み込みコマンドを試してEXIT
信号をトラップします。
#!/bin/bash
trap 'rm tmp' EXIT
if executeCommandWhichCanFail; then
mv output
else
mv log
exit 1 #Exit with failure
fi
exit 0 #Exit with success
のrm tmp
ステートメントはtrap
、スクリプトの終了時に常に実行されるため、ファイル「tmp」は常に削除されます。
インストールされているトラップもリセットできます。シグナル名のみでトラップを呼び出すと、シグナルハンドラーがリセットされます。
trap EXIT
詳細については、bashのマニュアルページを参照してください。man bash
まあ、ある種:
{ # your 'try' block
executeCommandWhichCanFail &&
mv output
} || { # your 'catch' block
mv log
}
rm tmp # finally: this will always happen
次の構文を使用して、スクリプトで成功を収めました。
# Try, catch, finally
(echo "try this") && (echo "and this") || echo "this is the catch statement!"
# this is the 'finally' statement
echo "finally this"
tryステートメントがエラーをスローするか、で終わるexit 1
場合、インタープリターはcatchステートメントに移動し、次にfinallyステートメントに移動します。
両方のtryステートメントが成功した場合(および/またはで終了した場合exit
)、インタープリターはcatchステートメントをスキップしてからfinallyステートメントを実行します。
Example_1:
goodFunction1(){
# this function works great
echo "success1"
}
goodFunction2(){
# this function works great
echo "success2"
exit
}
(goodFunction1) && (goodFunction2) || echo "Oops, that didn't work!"
echo "Now this happens!"
Output_1
success1
success2
Now this happens!
例_2
functionThrowsErr(){
# this function returns an error
ech "halp meh"
}
goodFunction2(){
# this function works great
echo "success2"
exit
}
(functionThrowsErr) && (goodFunction2) || echo "Oops, that didn't work!"
echo "Now this happens!"
Output_2
main.sh: line 3: ech: command not found
Oops, that didn't work!
Now this happens!
Example_3
functionThrowsErr(){
# this function returns an error
echo "halp meh"
exit 1
}
goodFunction2(){
# this function works great
echo "success2"
}
(functionThrowsErr) && (goodFunction2) || echo "Oops, that didn't work!"
echo "Now this happens!"
Output_3
halp meh
Oops, that didn't work!
Now this happens!
関数の順序が出力に影響することに注意してください。両方のステートメントを別々に試行およびキャッチする必要がある場合は、2つのtrycatchステートメントを使用してください。
(functionThrowsErr) || echo "Oops, functionThrowsErr didn't work!"
(goodFunction2) || echo "Oops, good function is bad"
echo "Now this happens!"
出力
halp meh
Oops, functionThrowsErr didn't work!
success2
Now this happens!
mv
2つのパラメーターを受け取るので、出力ファイルの内容を実際に確認したい場合があります。
echo `{ execCommand && cat output ; } || cat log`
rm -f tmp
それを行う別の方法は次のとおりです。
set -e; # stop on errors
mkdir -p "$HOME/tmp/whatevs"
exit_code=0
(
set +e;
(
set -e;
echo 'foo'
echo 'bar'
echo 'biz'
)
exit_code="$?"
)
rm -rf "$HOME/tmp/whatevs"
if [[ "exit_code" != '0' ]]; then
echo 'failed';
fi
上記は実際には何のメリットもありませんが、
set -e; # stop on errors
mkdir -p "$HOME/tmp/whatevs"
exit_code=0
(
set -e;
echo 'foo'
echo 'bar'
echo 'biz'
exit 44;
exit 43;
) || {
exit_code="$?" # exit code of last command which is 44
}
rm -rf "$HOME/tmp/whatevs"
if [[ "exit_code" != '0' ]]; then
echo 'failed';
fi
警告:出口トラップは常に実行されるとは限りません。この回答を書いた後、出口トラップが実行されず、ファイルが失われる状況に遭遇しました。その理由はまだわかりません。
この問題は、Pythonスクリプトをで停止したときに発生しました。PythonスクリプトはCtrl+C
、出口トラップを使用してbashスクリプトを実行しました。これにより、出口トラップがbashで実行されるため、実際には出口トラップが実行されSIGINT
ます。
したがって、trap .. exit
クリーンアップには役立ちますが、実行されないシナリオがいくつかあります。最も明白なシナリオは、停電と受信SIGKILL
です。
オプションを追加したり、オプションを変更したりすると、bashスクリプトが非常に大きくなることがよくあります。bashスクリプトに多くの関数が含まれている場合、「trapEXIT」の使用は簡単ではなくなる可能性があります。
たとえば、次のように呼び出されたスクリプトについて考えてみます。
dotask TASK [ARG ...]
それぞれTASK
がサブステップで構成されている場合があり、その間にクリーンアップを実行することが望ましい場合。
この場合、サブシェルを操作してスコープ付き出口トラップを生成すると便利です。
function subTask (
local tempFile=$(mktemp)
trap "rm '${tempFile}'" exit
...
)
ただし、サブシェルは親シェルのグローバル変数を設定できないため、サブシェルの操作には注意が必要です。
さらに、単一の出口トラップを作成することはしばしば不便です。たとえば、クリーンアップ手順は、エラーが発生する前に関数がどこまで到達したかによって異なる場合があります。RAIIスタイルのクリーンアップ宣言を作成できると便利です。
function subTask (
...
onExit 'rm tmp.1'
...
onExit 'rm tmp.2'
...
)
次のようなものを使用するのは明らかだと思われます
handlers=""
function onExit { handlers+="$1;"; trap "$handlers" exit; }
トラップを更新します。ただし、これはネストされたサブシェルでは失敗します。これは、親シェルのハンドラーの実行が早まるためです。クライアントコードはhandlers
、サブシェルの先頭で変数を明示的にリセットする必要があります。
[同じ信号に対して複数のbashトラップ]で説明されているソリューションは、からの出力を使用してトラップにパッチを適用しますが、同様に失敗します。サブシェルはトラップをtrap -p EXIT
継承しませんが、親シェルのハンドラーを表示するため、手動でリセットする必要があります。 。EXIT
trap -p exit