web-dev-qa-db-ja.com

シェルスクリプトのトラップ処理と暗黙のサブシェル

次のように、EXITトラップを介して何らかのクリーンアップコードを実行するシェルスクリプトがあるとします。

#!/bin/bash

mytrap () {
  echo "It's a trap!" >&2
}

trap mytrap exit

echo I am at the end of the script.

予想通り、これはIt's a trap!スクリプトが終了したとき:

$ sh myscript
I am at the end of the script.
It's a trap!

次のように、スクリプトを変更して、最終的に別のコマンドにパイプ処理される出力を生成する関数を追加します。

#!/bin/bash

mytrap () {
  echo "It's a trap!" >&2
}

myfunc () {
  echo "I've got a bad feeling about this..."
}

trap mytrap exit

myfunc | cat > /dev/null

echo I am at the end of the script.

パイプがあるため、myfuncのコードはサブシェルで実行されます...サブシェルは親のtrapの動作を継承していないように見えます。つまり、ここでアクションを実行すると発生しないトラップコードでクリーンアップする必要があります。

だからあなたはこれを試してください:

myfunc () {
  trap mytrap EXIT
  echo "I've got a bad feeling about this..."
}

そして、それでもサブシェルが終了するときにmytrapをトリガーできません。次のように、明示的なexitが必要であることがわかります。

myfunc () {
  trap mytrap EXIT
  echo "I've got a bad feeling about this..."
  exit
}

上記のコードでは、mytrapはサブシェルの終了時に適切にトリガーされます。

$ sh myscript 
It's a trap!
I am at the end of the script.
It's a trap!

それは予想される動作ですか?私はここでいくつかのことに驚いた:

  • trap設定はサブシェルに継承されませんでした
  • サブシェルからの暗黙の終了は、EXITトラップをトリガーするようには見えません
12
larsks

組み込みのbash trapでは、キーワードRETURNを使用できます。したがって、変更:

trap mytrap EXIT

に:

trap mytrap RETURN

Shell-builtinstrapの説明を参照してください

8
JRFerguson