以下のコードでeとoがサンプリング時間を設定した場合、最後の行が実行されないのはなぜですか?
set -x
set -e
set -o pipefail
add=$(echo 'x' |grep '1x' | wc -l)
echo $add
echo '1'
答え1
単一文字オプションを混在させるのではなく、-o option
すべての項目に長いオプション名を使用する方が明確です。
set -o xtrace -o errexit -o pipefail
where -o xtrace
is -x
, -o errexit
is -e
( pipefail
, kshでは、他のほとんどのシェルで見つかり、まもなく標準になり、ほとんどのシェルには対応する単一文字がありません)
errexit
つまり、未処理のコマンドが失敗した場合、スクリプトは終了します。pipefail
つまり、パイプラインのコンポーネントのいずれかが失敗すると、パイプライン全体が失敗したと見なされます(そうでない場合は、最も右側のコンポーネントのみが考慮されます)。
したがって、echo 'x' |grep '1x' | wc -l
これら3つのコマンド(echo
、、grep
および)wc
のいずれかが失敗すると、パイプラインは失敗します。
ここでは、出力に含まれる行がgrep
見つからないため、失敗が報告されます。これは、同じ失敗したシャットダウン状態で実行されているサブシェルを終了するためです。結果の割り当ても失敗し、スクリプトを実行するシェルは終了します。1x
echo
errexit
$(...)
var=$(...)
grep | wc -l
このように書くのがより良いことに注意してくださいgrep -c
。
効果を避けるには、errexit
エラーを処理するだけです。
それは次のとおりです。
var=$(echo x | grep -c 1x || : no match should not be a fatal error)
|| another command
パイプラインの後、失敗はシェルによって手動で処理されると見なされるため、これにはerrexit
適用されません。ここでは、コマンドは:
何も正常に実行しません(true
何もしない引数を許可することを除く)。
処理中のパイプラインエラーです。エラーを個別に処理することもできますgrep
。
var=$(
echo x | {
grep 1x || : no match should not be a fatal error
} | wc -l
)
スクリプトが失敗echo
またはwc
終了することを許可します(ここにはスクリプトを実行するための追加のサブシェルが含まれますgrep || :
)。
または、割り当て失敗を処理します。
var=$(echo x | grep -c 1x) || : no match should not be a fatal error
サブシェル内で無効にするかどうかは、シェルerrexit
とそのバージョンによって異なります。たとえば、一部のシェルは出力x
し、他のシェルは空の行を出力しますsh -ec 'v=$(false; echo x) || true; echo "$v"'
。
errexit
(別名set -e
)は非常に脆弱な機能です。最も単純なスクリプト以外の目的で使用したり、代わりに手動エラー処理を実行したりすることはお勧めできません。他のプログラミング言語と同様に、スクリプト内のすべてのコマンドラインが失敗した場合に何が起こるのかを諦めてください。