サブシェルでシェルスクリプトを終了する

サブシェルでシェルスクリプトを終了する

次のスニペットを検討してください。

stop () {
    echo "${1}" 1>&2
    exit 1
}

func () {
    if false; then
        echo "foo"
    else
        stop "something went wrong"
    fi
}

通常、呼び出されるとfuncスクリプトは終了し、これは予想される動作です。ただし、サブシェルで実行される場合は次のようになります。

result=`func`

スクリプトを終了しません。これは、呼び出しコードが毎回関数の終了状態をチェックする必要があることを意味します。これを避ける方法はありますか?これがset -e目的ですか?

答え1

たとえば、終了ステータス77を設定して、任意のレベルのサブシェルを終了して実行できます。

set -E
trap '[ "$?" -ne 77 ] || exit 77' ERR

(
  echo here
  (
    echo there
    (
      exit 12 # not 77, exit only this subshell
    )
    echo ici
    exit 77 # exit all subshells
  )
  echo not here
)
echo not here either

set -EERRこの改善されたバージョンはトラップと組み合わせて、set -eユーザーが自分のエラー処理を定義できるようにします。

zshではERRトラップが自動的に継承されるため、必要はありません。トラップを関数として定義し、次のように変更することもできset -Eます。TRAPERR()$functions[TRAPERR]functions[TRAPERR]="echo was here; $functions[TRAPERR]"

答え2

あなたできるkill $$()を呼び出す前に元のシェルを終了するとexit機能します。しかし:

  • 私の考えでは醜いと思います。
  • 2番目のサブシェルがある場合、つまりサブシェル内のサブシェルを使用すると破損します。

代わりに、次のいずれかを使用できます。Bash FAQから値を返すさまざまな方法。残念ながら、ほとんどはあまり良くありません。各関数呼び出し後にエラーを確認することもできます(-e質問が多い)。これを行うか、代わりにPerlを使用してください。

答え3

代わりに、ネストされたサブシェル(すべての呼び出し元とワーカープロセスがシグナルを受け取る)で動作することを試してみることkill $$もできますが、...それでも残酷で見苦しいです。kill 0

答え4

一行の私の出口の例:

COMAND || ( echo "ERROR – executing COMAND, exiting..." ; exit 77 );[ "$?" -eq 77 ] && exit

関連情報