3

私はbashスクリプトを書いていますが、最初のエラーでクラッシュさせたいのですが。ただし、以下で簡略化した特定の状況では、これを実行することはできません。

#!/bin/bash
set -Exu
bad_command() {
  false
  #exit 1
  echo "NO!!"
}
(set -o pipefail; bad_command | cat ; echo "${PIPESTATUS[@]}; $?") || false
echo "NOO!!"

予想される動作は、bad_commandサブシェルのクラッシュ、()サブシェルのクラッシュへの伝播、外部シェルのクラッシュへの伝播です。しかし、これらはいずれもクラッシュせず、両方のNOが出力されます(!?)

ステートメントのコメントを外すとexit 1、NOは出力されなくなりますが、NOOはまだ出力されます(!?)

3つのシェルのそれぞれの内部で明示的に使用してset -eみました(関数の最初の行、後の最初のステートメント(ですが、変更はありません。

注:()これはより複雑なスクリプトを単純化したものであるため、サブシェル内でパイプを実行する必要があります。サブシェルがないと、すべてが期待どおりに機能し、またはのいずれか()でNOは発生しません。falseexit 1

4

2 に答える 2

0

これはbashまたはPOSIXのバグのようです:https ://groups.google.com/forum/?fromgroups =#!topic / gnu.bash.bug / NCK_0GmIv2M

于 2012-12-14T14:32:42.570 に答える
0

同じ問題が発生した後、回避策を見つけました。あなたが達成したいことに応じて実際には3。

最初に、終了コードを処理するために追加の作業が必要になるため、OPサンプルコードを少し書き直します。

#! /bin/bash
set -eEu
bad_command_extra() {
        return 42
}
bad_command() {
  bad_command_extra
  echo "NO!!"
}

if bad_command; then echo "NOO!!"; else echo "errexit worked: $?"; fi

errexitを機能させるだけでよい場合は、を呼び出すには次の手順で十分bad_commandです。秘訣はbad_command、バックグラウンドで起動することです。

(bad_command) &
bc_pid=$!
if wait $bc_pid; then echo "NOO!!"; else echo "errexit worked: $?"; fi

出力も(と同様にabc=$(bad_command))操作する場合は、通常どおり一時ファイルにキャプチャします。

tmp_out=$(mktemp)
tmp_err=$(mktemp)
(bad_command >$tmp_out 2>$tmp_err) &
bc_pid=$!
if wait $bc_pid; then echo "NOO!!"; else echo "errexit worked: $?"; fi
cat $tmp_out $tmp_err
rm -f $tmp_out $tmp_err

最後に、テストで、waitコマンドが0または1を返したが、bad_command(bash 4.3.42)の実際の終了コードは返さなかったことがわかりました。これには、さらに作業が必要です。

tmp_out=$(mktemp)
tmp_err=$(mktemp)
tmp_exit=$(mktemp)
echo 0 > $tmp_exit
(
        get_exit () {
                echo $? > $tmp_exit
        }
        trap get_exit ERR
        bad_command >$tmp_out 2>$tmp_err
) &
bc_pid=$!
bc_exit=$(cat $tmp_exit)
if wait $bc_pid
then echo "NOO!!"
else echo "errexit worked: $bc_exit"
fi
cat $tmp_out $tmp_err
rm -f $tmp_out $tmp_err $tmp_exit

奇妙な理由で、if前と同じように1行に入力すると、この場合は終了コード0になります。

于 2016-06-29T19:17:10.367 に答える