私はいくつかのコードをテストするためにBashでスクリプトを書いています。しかし、最初にコードのコンパイルが失敗した場合、テストを実行するのは馬鹿げているように見えます。その場合は、テストを中止します。
スクリプト全体をwhileループの内側にラップし、ブレークを使用せずにこれを実行できる方法はありますか? dun dun dun gotoのようなものですか?
set -e を使用
#!/bin/bash
set -e
/bin/command-that-fails
/bin/command-that-fails2
スクリプトは失敗した最初の行の後で終了します(ゼロ以外の終了コードを返します)。この場合、 command-that-fails2 は実行されません。
すべてのコマンドのリターンステータスを確認すると、スクリプトは次のようになります。
#!/bin/bash
# I'm assuming you're using make
cd /project-dir
make
if [[ $? -ne 0 ]] ; then
exit 1
fi
cd /project-dir2
make
if [[ $? -ne 0 ]] ; then
exit 1
fi
set -e を指定すると、次のようになります。
#!/bin/bash
set -e
cd /project-dir
make
cd /project-dir2
make
失敗したコマンドはスクリプト全体を失敗させ、終了ステータスを返します。 $?で確認できます。 。スクリプトが非常に長い場合や、たくさんのものを作成している場合は、どこにリターンステータスチェックを追加しても、かなり醜くなります。
悪いお尻のSysOpsの男がかつて私にThree-Fingered Clawのテクニックを教えてくれました:
yell() { echo "$0: $*" >&2; }
die() { yell "$*"; exit 111; }
try() { "$@" || die "cannot $*"; }
これらの機能は* NIX OSとシェルのフレーバーロバストです。それらをあなたのスクリプトの先頭(bashかそれ以外)に置き、try()
あなたのステートメントとコードを書いてください。
( 飛んでいる羊に コメント)。
yell
:stderr
:へのスクリプト名とすべての引数を表示します。$0
はスクリプトへのパスです。$*
はすべて引数です。>&2
は>
は標準出力を&pipe 2
にリダイレクトします。 pipe 1
はそれ自身stdout
になります。die
はyell
と同じように機能しますが、 0以外の終了ステータス で終了します。これは「失敗」を意味します。try
は||
(boolean OR
)を使います。これは左側が失敗しなかった場合にのみ右側を評価します。$@
もまたすべての引数ですが、 異なる です。それがすべてを説明してくれることを願っています。
source
を指定してスクリプトを呼び出す場合は、return <x>
を使用できます。ここで<x>
はスクリプトの終了ステータスになります(errorまたはfalseにはゼロ以外の値を使用します)。スクリプトをsource
にしても(つまり、直接そのファイル名で)実行しても、これは期待通りに動作しますが、return文は文句を言うでしょう(エラーメッセージ "return:return"は 'からのみ' '関数またはソーススクリプト ")。
代わりにexit <x>
を使用した場合、スクリプトがsource
を指定して呼び出されると、スクリプトを開始したシェルが終了しますが、実行可能スクリプトは直接正常に実行されます。
どちらの場合も同じスクリプトで処理するには、次のようにします。
return <x> 2> /dev/null || exit <x>
どちらの呼び出しが適していても、これが処理されます。
注:<x>
は単なる数字になっています。
私はしばしばエラーを処理するためにrun()と呼ばれる関数を含みます。私がしたいすべての呼び出しはこの関数に渡されるので、失敗したときにスクリプト全体が終了します。 set -eソリューションよりも優れているこの利点は、行が失敗したときにスクリプトがサイレントモードで終了しないことです。そして、問題が何であるかを知ることができます。次の例では、falseの呼び出しでスクリプトが終了するため、3行目は実行されません。
function run() {
cmd_output=$(eval $1)
return_value=$?
if [ $return_value != 0 ]; then
echo "Command $1 failed"
exit -1
else
echo "output: $cmd_output"
echo "Command succeeded."
fi
return $return_value
}
run "date"
run "false"
run "date"
if
構文の代わりに、 短絡評価 を利用することができます。
#!/usr/bin/env bash
echo $[1+1]
echo $[2/0] # division by 0 but execution of script proceeds
echo $[3+1]
(echo $[4/0]) || exit $? # script halted with code 1 returned from `echo`
echo $[5+1]
交代演算子の優先順位のために必要な括弧のペアに注意してください。 $?
は、最近呼び出されたコマンドの終了コードに設定された特別な変数です。
私は同じ質問をしていますが、それは重複しているのでそれを尋ねることはできません。
スクリプトがもう少し複雑な場合、exitを使用して受け入れられた答えは機能しません。バックグラウンドプロセスを使用して状態をチェックする場合、exitはサブシェルで実行されるため、そのプロセスのみを終了します。スクリプトを強制終了するには、明示的にそれを強制終了する必要があります(少なくともそれが私が知る唯一の方法です)。
これを実行する方法についての小さなスクリプトです。
#!/bin/bash
boom() {
while true; do sleep 1.2; echo boom; done
}
f() {
echo Hello
N=0
while
((N++ <10))
do
sleep 1
echo $N
# ((N > 5)) && exit 4 # does not work
((N > 5)) && { kill -9 $$; exit 5; } # works
done
}
boom &
f &
while true; do sleep 0.5; echo beep; done
これはより良い答えですが、それでも不完全なものです/ ブーム の部分を取り除く方法が本当にわかりません。