次のスクリプトがありますsandbox.sh
。
#!/bin/bash
set -eu -o pipefail -E
function func1() {
echo "FUNC1"
exit 1
}
function func2() {
local ret
ret=$(func1)
echo $ret
echo "(func2)This line shouldn't be reached:'${?}'" >&2
}
var=$(func1) # The Line
echo "main:This line shouldn't be reached:'${var}':'${?}'" >&2
(GNU bash、バージョン4.4.20(1)-リリース(x86_64-pc-linux-gnu))
期待どおり実行が停止します。
$ bash -eu sandbox.sh
$
ただし、「The Line」を変更して を呼び出すと、次var=$(func2)
のような出力が得られます。func1
func2
$ bash sandbox.sh
(func2)This line shouldn't be reached:'0'
main:This line shouldn't be reached:'FUNC1':'0'
$
私にとって、コマンドの置き換えは関数の内部に置かれたときに異なる動作をするようですが、bashがなぜこのように設計されているのかわかりません。さらに、ある関数の出力を別の関数で使用することもでき、これらの違いは混乱している。
注:以下のようにfunc2を書き換えると
function func2() {
func1
}
スクリプトはThe Lineで停止します。しかし、私はプログラマーがfunc1の出力を操作したい場合が多いと思います。
ベストアンサー1
時間を費やすことで、これらすべてを完全に理解できます。より多くのロギングが必要なので、実行してください。強く打つ引数を使用すると、-x
bashがコマンドを実行する前に前に+
。
最初の実行
$ bash -x sandbox.sh; echo $?
+ set -eu -o pipefail -E
++ func1
++ echo FUNC1
++ exit 1
+ var=FUNC1
1
-e
説明するこれコマンドがゼロ以外の値を返すと、シェルはすぐに終了します。ただし、func1
サブシェルで実行(使用)することが重要です$(
)
。上記のトレースは、2つの+
sをプレフィックス()として使用して++
これを示しています。- サブシェルはstdoutに出力を印刷
FUNC1
し、戻りコード1で終了します。- 注:
-e
このサブシェル内で閉じます。サブシェルが終了した理由はコマンドのためでしたexit
。-e
書かれたfunc1
方法では実際にはわかりません。
- 注:
- 最初のシェルに戻り、
FUNC1
変数に代入します。変わりやすい。ただし、この割り当てコマンドの終了コードは最後のコマンド置換の終了コードです。。吹くこの失敗(つまり、ゼロ以外の終了コード)を確認して終了します。
リファレンスマニュアル簡単なコマンド拡張部分:
いずれかの拡張にコマンド置換が含まれている場合、そのコマンドの終了ステータスは、最後に実行されたコマンド置換の終了ステータスです。
2回目の実行
最初の実行とまったく同じ説明です。私たちはこれが-e
サブシェル内では機能しないことをもう一度強調します。しかし、今回は大きな違いが1つあります。つまり、何が起こっているのかをはるかに明確に知ることができます。
- 終了コードは、
func2
最後のコマンドの終了コードです。 - それは
echo
常に効果があります。 func2
常に成功- ミッションは常に成功します。
-e
効果はありません。
shopt -s inherit_errexit
?
これはサブシェルで開きます-e
。しかし、これは難しい仲間です。コマンドが失敗したときにアサーションする保証はありません。
考えてみてください:
set -e
shopt -s inherit_errexit
f() { echo a; (exit 22); echo b; }
echo "f says [$(f)] $?"
echo byee
echo
今回は、コマンド置換が代入の一部ではなく値の一部なので、次のような結果が得られます。
+ set -e
+ shopt -s inherit_errexit
++ f
++ echo a
++ exit 22
+ echo 'f says [a] 22'
f says [a] 22
+ echo byee
byee
- サブシェルは終了コード22で失敗したコマンドをチェックします。コマンドは
-e
有効なので、シェルはコード22(echo b
実行なし)で終了します。 - 最初のシェル、
echo
取得したa
出力、f
および22
サブシェルの終了コードを返します。 - 問題は、割り当てとは異なり、終了コード
echo
が0であることです。
バージョン
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.