web-dev-qa-db-ja.com

シェルを終了せずに関数スタックを終了する

私はスクリプトを書いていたときに、奇妙な問題に遭遇しました。文字列を出力して終了するエラー関数を呼び出す可能性のある一連の関数を含むスクリプトを入手した場合、シェルは終了します。なぜそれができるのか知っています。これは、関数呼び出しが呼び出し元と同じプロセス空間にあるためです(少なくともbashにあります)。関数内の出口は、提供された終了コードで現在のプロセスを終了します。例:

error()
{
  echo $1
  exit 1
}

fn()
{
  if [ $# == 0 ]; then
    error "Insufficient parameters."
  fi
  # do stuff
}

$ fn
Insufficient parameters.
[Shell terminates]

だから私の質問は、現在のシェルを終了せずに新しいサブシェルを生成せずに、関数スタックのすべての関数を終了できるでしょうか?

ありがとう

36
Adrian

シェルを終了せずに関数スタックを終了するには、次のコマンドを使用できます。

kill -INT $$

pizza で述べたように、これはCtrl-Cを押すのと同じです。これにより、現在のスクリプトの実行が停止され、コマンドプロンプトが表示されます。


注:私が pizza の回答を選択しなかった唯一の理由は、これが彼/彼女の回答に埋もれていて直接回答されなかったためです。

34
Adrian

あなたはできる

exit() { return $1;}

その後

source ./your_script 

懐疑論者への回答として、これは現在のシェルにのみ影響し、スポーンしたシェルには影響しません。

より有益なフォームは

exit() {
    local ans
    local line
    read -p "You really want to exit this? " line
    ans=$(echo $line)
    case "$ans" in
            Y);;
            y);;
            *)kill -INT $$;;
    esac
    unset -f exit
    exit $1
}
9
pizza

関数のそれぞれにreturnステートメントを追加して、関数が呼び出す関数の戻り値を確認する必要があります。ファイルのソーシングは、$BASH_SOURCEなどの変数を除いて、現在のコンテキストにコードを切り取って貼り付けるようなものです。

または、fnをシェルスクリプトとして定義して、exitが必要なことを実行できるようにします(フォークが高すぎる場合を除く)。

6
l0b0

returnステートメントを使用しますが、呼び出しエラーの後にreturnを追加する必要があります

2

シェルには、一度に多くの関数呼び出しを巻き戻すための例外メカニズムはありません。戻り値を確認し、手動で最後まで返す必要があります。

2
Mark Reed