2

次のレシピをtime falseアンダーにset -e成功させます (time出力が見えるという意味での成功):

(
set +e
time { ( set -e; false; echo no0; ); }
echo yes0 $?
)

ただし、次のレシピは失敗します。

(
set -e
time false
echo no1
)

同じように:

(
set -e
time { false; echo no2; }
echo no2
)

同様に (驚くべきことに、bash3 では yes3 を出力し、bash4 では何も出力しません):

(
set -e
time ( false; echo no3; )
echo yes3 $?
)

同様に(それほど驚くべきことではありません):

(
set +e
time { set -e; false; echo no4; }
echo no4
)

同様に(驚き):

(
set +e
time ( set -e; false; echo no5; )
echo yes5 $?
)

以下は bash3 では成功し、bash4 ではまったく異なることを行います。

(
set -e
time { ( false; echo no7; ); echo yes6 $?; }
echo yes6 $?
)

echo「いいえ」は出力されませんが、「はい」はbash3によって出力されることに注意してください(ただし、すべてがbash4によって出力されるわけではありません)。

これを(...)下のサブシェル処理と比較すると、この場合、ビルトインはサブシェル コンテキストで実行されているset -eように見えます。なんてこと?timetime (...)

でテスト済み

GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

出力

real    0m0.000s
user    0m0.001s
sys     0m0.000s
yes0 1
yes3 1
yes5 1
yes6 1

real    0m0.000s
user    0m0.000s
sys     0m0.001s
yes6 0

GNU bash, version 4.1.5(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.

出力

real    0m0.001s
user    0m0.000s
sys     0m0.004s
yes0 1
yes5 1

「yes3」と「yes6」のケースでは、bash3 と bash4 の処理方法が大きく異なることに注意してくださいset -e

しかし、「yes5」のケースは混乱を招きます。「時間」は、外部シェルではなくサブシェルによって何らかの形で処理されているようです。

この動作は POSIX によって強制されますか、bash の 1 つにバグがありますか、それとも単なるbash特別な動作ですか?

ありがとう ;)

PS: なぜこれがアカデミックではないのか不思議に思っている方のために: 以前set -e("yes3" without time) の下でスクリプトが実行されていました。いくつかのタイミング情報をログに記録するように変更されました。ハックは「yes6」のように見えます。しかし、現在 bash4 が登場しており、再度修正が必要です。

4

1 に答える 1

2

実際、bash4の動作は予測可能です。

  • set -e現在のシェルまたは現在のシェルのサブシェルの単純なコマンドがゼロ以外の終了ステータスを返した場合、現在のシェルを終了します(より詳細で正確な説明については、Bashのマニュアルのセクションを参照してsetください) 。

  • set -e優先されますtime、つまり、no2の場合

    (
       set -e
       time false;  
    )
    

    実行を終了する前にサブシェルtimeを終了するため、からの出力はありませんtime


そのことを念頭に置いて、yes5( )の場合に何が起こるか(1番目を「サブシェルレベル1」、2番目( )を「レベル2」 と呼びましょう)

(
    set +e
    time ( set -e; false; echo no5; )
    echo yes5 $?
)

falseこれは、終了ステータス1を返すに遭遇した場合です。これset -eにより、サブシェルレベル2が終了し、終了ステータス1がサブシェルレベル1に戻ります。ただし、レベル1にはが含まれているset +eため、すべてが実行されます。


yes6場合、

(
    set -e
    time { ( false; echo no7; ); echo yes6 $?; }
    echo yes6 $?
)

falseサブシェルレベル2ではトリガーが返されるためset -e、出力がありません。


残りは読者のための練習問題として残されています。

于 2012-10-23T17:50:45.960 に答える