web-dev-qa-db-ja.com

Bash関数内でゼロ以外の終了ステータスをキャッチして処理する方法は?

次の(無意味な)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 $?
}

しかし、これはひどく反復的で醜いようです。これをクリーンアップする別の方法はありますか?

4
smitelli

set -efailfailfailが存在しないと、スクリプト全体(または関数がサブシェルで実行されている場合はサブシェル)が終了します。

関数からシェルの状態を変更する必要がない場合は、サブシェルで実行できます。

myfunc() (
    set -e
    ls
    failfailfail
    uptime
)

Bashの別のアプローチは、ERRtrap を設定して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 $?
}
0
Julie Pelletier

これらはすべて単純なコマンドなので、次のように実行できます。

myfunc() {
  ls &&
  failfailfail &&
  uptime ||
  return $?
}
0
Wildcard

このようなことを処理するMakefileに物事を入れる方が良い場合があります。

#!/bin/bash
myfunc() { # watch out for tabs!
        make -f - <<!
default:
        ls -d
        failfailfail
        uptime
!
}
0
meuh