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


83

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

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

しかし、次のように呼び出された場合、それは機能しないことに気づきました。

res=$(func)

サブシェルを作成し、「exit 1」がプライマリではなく、そのサブシェルを中止することを理解しています。

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

回答:


90

あなたは何もできません、ためトップレベルのシェルレジスタです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"。このシェルは、提供されたコマンド(この場合は)を使用してキャッチおよび処理されます。


1
私はCsetsid()関数について考えていましたが、まったく同じようには機能しません。setsid新しいプロセスを開始する必要があるため、コマンドを使用しないように更新されました。
fatalError 2012年

3
動作します。あらゆるレベルの関数の入れ子、あらゆるフロー...ただ機能します。
LiMar 2012年

これから、最初の引数のコードを使用して終了する一般的なabort()関数を作成することは可能ですか? abort 2ですか?、trap "exit 2" TERMbeforeを実行しkillますか?
Neil C. Obremski 2013年

@ NeilC.Obremski:もちろんです。これは主に、値を取得してトップレベルのシェルに戻す方法の問題です。おそらくtempfile、最上位のシェルにコードを格納する場所を選択するなどのコマンドを使用し、終了するシェルにそのファイルにコードを書き込んでから、親のハンドラーで読み取ります。
fatalError 2013年

2
サブシェルが介在していると機能しないようです。set -E ここ
Ron Burk 2015年

42

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

set -e 
func
set +e

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

(func) || exit $?

3
興味深いことに、私は解決策を見ています。メインスクリプトの「set-e」により、1を返す(またはそれを終了する)関数は実行全体を中止します。残念ながら、「set -e」はすべての動作を大幅に変更するため、使用できません。
LiMar 2012年

1
数値比較には(())を使用する必要があります。[] -gt、-eqなどの内部を使用する必要があります。
jordanm 2012年

16
またはres=$(func) || exit
グレンジャックマン2012年

@glennjackmanがCookieを取得すると思います。それは私が持っているゴミよりもはるかにきれいです!
brice 2012年

3
そのようなものは質問の精神に逆らいます。すべての関数呼び出しがエラー自体をキャッチする必要がある場合、そもそも使用exit しても意味がありません。関数は単に戻ることができます。/ただし、set -eがグローバルに設定されている場合、これは理にかなっています
phil294 2017

2

私はより良いと思います

#!/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"

1

子プロセスは、親プロセスを強制的に閉じることはできません。ある種のシグナリングメカニズムを使用する必要があります。オプションには、特別な戻り値が含まれる場合やkill、次のようなシグナルを送信する場合があります。

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

1

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

番号。

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

あなたはできる

res=$(func)
echo $?
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.