Errtraceとローカル

Errtraceとローカル

次のスクリプトを使用しています。

#!/bin/bash -Eu

trap 'echo Hi' ERR

exit_failure() {
  echo "Hello, World!"
  return 1
}

sub_failure() {
  res=$(exit_failure)
}

sub_failure

結果は次のとおりです。

Hi
Hi

しかし、sub_failure()次のように変更した場合:

sub_failure() {
  local res=$(exit_failure)
}

もはや出力が出ませERRんか?信号が隠されているのはなぜですか?ERRローカル変数を使用するにはどのようにキャプチャする必要がありますか?できることはわかりますが、local res; res=$(exit_failure)なぜそれらを分離する必要がありますか?

ベストアンサー1

これは間違いではありません。これは実際に定義された動作です。

あなたがそれを使用するとbash -Eux何が起こるのかを見ることができます。 (-Euあなたのshebangで+ -x

+ trap 'echo Hi' ERR
+ sub_failure
++ exit_failure
++ echo 'Hello, World!'
++ return 1
+++ echo Hi
+ res='Hello, World!
Hi'
++ echo Hi
Hi
++ echo Hi
Hi

コマンド置換を実行すると、スイッチtrapによって-E継承されます。したがって、関数return 1によってトリガされた継承トラップの「Hi」は。 (実行バリアントを使用する場合も同様です)exit_failure()retlocal

また、res=...式は1(エラー)を返し、トラップ(sub_failure()関数内)をトリガーします。

res=...関数のreturnと結果は1関数の最後のコマンドの結果であるため、結果もエラーであり、sub_failure()メインシェルで実行1後にトラップが再トリガされます。sub_failureしたがって、2つの「Hi」が表示されます。 forres=....とforsub_failureと隠された「Hi」がに保存されます$res

localそれではバリエーションについて話しましょう。

+ trap 'echo Hi' ERR
+ sub_failure
++ exit_failure
++ echo 'Hello, World!'
++ return 1
+++ echo Hi
+ local 'res=Hello, World!
Hi'

定義によると、関数内で使用されるときはlocal常に返されます。評価結果も返されるため、隠された「Hi」を保存しながら(成功)と評価することになります0。したがって、今回は「隠された」失敗1つと成功2つを得ることになります。local res=...0$resres=..0 sub_failure0

このスレッドは古いですが、役に立つことを願っています。 ;)

local res=...また、私たちが分割しなければならない理由も明らかです。

local res
res=....

最初のバリエーションの動作を復元します。 ;)

おすすめ記事