次の(無意味な)Bash関数があるとします。
myfunc() {
ls
failfailfail
uptime
}
次のように実行します。
myfunc || echo "Something is wrong."
私が起こしたいのは、ls
が実行されて(本来どおり)、failfailfail
が機能しない(存在しないため)、およびuptime
が実行されないことです。関数の戻り値はゼロ以外になり、エラーメッセージが表示されます。戻り値は、失敗したコマンドの正確な終了ステータスである必要はなく、ゼロであってはなりません。
実際に起こるのは、ls
の出力に続いて "-bash:failfailfail:command not found"が表示され、その後にuptime
の出力が表示されます。失敗した終了ステータスが食べられているため、エラーメッセージは表示されません。
set -e
は、関数内でも、関数が呼び出されるスコープ内でも、効果はありません。これを希望どおりに機能させる唯一の方法は次のとおりです。
myfunc() {
ls || return $?
failfailfail || return $?
uptime || return $?
}
しかし、これはひどく反復的で醜いようです。これをクリーンアップする別の方法はありますか?
下 set -e
、failfailfail
が存在しないと、スクリプト全体(または関数がサブシェルで実行されている場合はサブシェル)が終了します。
関数からシェルの状態を変更する必要がない場合は、サブシェルで実行できます。
myfunc() (
set -e
ls
failfailfail
uptime
)
Bashの別のアプローチは、ERR
trap を設定してreturn
を実行することです。ローカル設定にしたい場合は、少し面倒な古いトラップ値を復元する必要があります。
myfunc() {
local old_ERR_trap=$(trap -p ERR)
if [[ -z $old_ERR_trap ]]; then old_ERR_trap="trap - ERR"; fi
trap 'local ret=$?; eval "$old_ERR_trap"; return $ret' ERR
ls
failfailfail
uptime
}
単純にする唯一の方法は、すべてを1つのコマンドにまとめることですが、スクリプトを以前のバージョンよりも維持するのが少し難しくなります。
myfunc() {
ls && failfailfail && uptime || return $?
}
これらはすべて単純なコマンドなので、次のように実行できます。
myfunc() {
ls &&
failfailfail &&
uptime ||
return $?
}
このようなことを処理するMakefileに物事を入れる方が良い場合があります。
#!/bin/bash
myfunc() { # watch out for tabs!
make -f - <<!
default:
ls -d
failfailfail
uptime
!
}