web-dev-qa-db-ja.com

サブシェルでset -e

set -eは、トップシェルと同じようにサブシェルにも影響があると思いました。どうやら、そうではありません。この:

(
  set -e
  false 
  true
) || echo false1


bash -ec '
  set -e
  false 
  true
' || echo false2


bash <<EOF || echo false3
  set -e
  false 
  true
EOF

bash <<EOF || echo false4
  false 
  true
EOF

bash <<EOF || echo false5
  false  &&
  true
EOF

プリント

false2
false3
false5

これはどこに文書化されていますか?すべてのコマンドを&&で接続せずに(または各コマンドの後に|| exit $?を実行せずに)エラーでサブシェルを終了させることはできますか?

編集:

私の特定のユースケースは次のようなものでした:

set -e
  # ...
status=0
( false; true ) || status=$?
report_code $status
return $status

サブシェルの内容は私の実際のコードでした。これの問題は、常にステータスを0に設定し、||;で置き換えると、外側のセット-eが原因で不要なエラー終了が発生することです。

私はそれを解決しました:

set -e
  # ...
set +e
( false; true ); status=$?
set -e
report_code $status
return $status

私はこれを実行する必要がなかったと思いますが、すべての一般的なシェルは、この実行されたサブシェルとフォークされたサブシェルの二分法を示しているようです:

#!/bin/sh

echo FORK\'D:
export SH
for SH in dash bash ksh zsh; do
    $SH -c 'st=0; ( set -e; false; true ) || st=$?; printf "%s\t%s\n" $SH  $st; '
done

echo EXEC\'D:
for SH in dash bash ksh zsh; do
    $SH -c 'st=0; '$SH' -c " set -e; false; true " || st=$?; printf "%s\t%s\n" $SH $st; '
done

出力:

FORK'D:
dash    0
bash    0
ksh 0
zsh 0
EXEC'D:
dash    1
bash    1
ksh 1
zsh 1
8
PSkocik

観察する:

$ ( set -e; false ; true ) || echo false1
$ ( set -e; false ; true ) ; echo code=$?
code=1

また:

$ ( set -e; false ; true; echo inside=$? ) || echo false1
inside=0

どうやら、サブシェルの後に||が続いている場合、set -efalseコマンドに到達してもサブシェルを終了させません。代わりに、サブシェルはtrue(およびecho inside=$?)を続行して実行します。

set -eの哲学は、通常、キャッチされないエラーが発生した場合にのみ終了することです。ここで、サブシェルの外側に||が存在すると、サブシェル内のエラーが「キャッチ」され、falseの後にset -eが終了しないことをシェルに伝えているようです。

set -eには、多くの驚くべき動作があります。 「-eが設定されていないのはなぜですか?」)を参照してください

ドキュメンテーション

上記の動作は、man bashのドキュメントに示されています。

-e

パイプライン(単一の単純なコマンドで構成される場合があります)、リスト、または複合コマンド(上記のシェルGRAMMARを参照)がゼロ以外のステータスで終了した場合は、すぐに終了します。 失敗したコマンドがコマンドリストの一部(whileまたはuntilキーワードの直後)、テストの一部(ifまたはElifの予約語、&=または||で実行されるコマンドの部分list最後の&&または||に続くコマンド、パイプライン内の最後以外のコマンド、またはコマンドの戻り値が!で反転されている場合を除く。 -eが無視されている間にコマンドが失敗したため、サブシェル以外の複合コマンドがゼロ以外のステータスを返した場合、シェルは終了しません。設定されている場合、ERRのトラップはシェルが終了する前に実行されます。このオプションは、シェル環境と各サブシェル環境に個別に適用され(上記のコマンド実行環境を参照)、サブシェル内のすべてのコマンドを実行する前にサブシェルが終了する可能性があります。 [強調が追加されました。]

13
John1024