web-dev-qa-db-ja.com

どのように呼び出されても、実行全体を中止するbash関数を記述する方法はありますか?

私はbash関数で「exit 1」ステートメントを使用してスクリプト全体を終了しましたが、正常に機能しました。

function func()
{
   echo "Goodbye"
   exit 1
}
echo "Function call will abort"
func
echo "This will never be printed"

しかし、次のように呼び出されたとき、それは仕事をしないことに気付きました:

res=$(func)

サブシェルを作成し、「exit 1」がそのサブシェルをアボートし、プライマリサブシェルはアボートしないことを理解しています。

しかしどのように呼び出されても実行全体を中止する関数を書く方法はありますか?本当の戻り値を取得する必要があります(関数によってエコーされます)。

68
LiMar

couldを実行すると、TERMシグナルのトップレベルシェルを登録して終了し、TERMをトップレベルシェルに送信します。

#!/bin/bash
trap "exit 1" TERM
export TOP_PID=$$

function func()
{
   echo "Goodbye"
   kill -s TERM $TOP_PID
}

echo "Function call will abort"
echo $(func)
echo "This will never be printed"

したがって、関数はTERM信号をトップレベルのシェルに送り返します。これは、提供されたコマンド(この場合は"exit 1"

79
FatalError

set -e which コマンドがゼロ以外のステータスで終了した場合に終了 を使用できます:

set -e 
func
set +e

または、戻り値を取得します。

(func) || exit $?
34
brice

しかし、どのように呼び出されても、実行全体を中止する関数を記述する方法はありますか?

いいえ

実際の戻り値を取得する必要があります(関数によってエコーされます)。

できます

res=$(func)
echo $?
1
Luca

子プロセスは、親プロセスを暗黙的に閉じることはできません。何らかの種類の信号メカニズムを使用する必要があります。オプションには特別な戻り値が含まれるか、killを使用して何らかの信号を送信する場合があります。

function child() {
    local parent_pid="$1"
    local other="$2"
    ...
    if [[ $failed ]]; then
        kill -QUIT "$parent_pid"
    fi
}
0
Daenyth

私はより良いと思います

#!/bin/bash
set -e
trap "exit 1" ERR

myfunc() {
     set -x # OPTIONAL TO SHOW ERROR
     echo "Exit with failure"
     set +x # OPTIONAL
     exit 1
}
echo "BEFORE..."
myvar="$(myfunc)"
echo "AFTER..But not shown"
0
AmazingAlex