bashコードを書いているときにエラーが発生した場合は、スクリプトを終了したいと思います。 set -eトリックはうまく機能しますが、サブシェルでは機能しません。以下は簡単な例です。
set -e
chmod a=r file.txt
x=`grep value file.txt | awk '{print $2*2}'`
echo "okay, x=$x"
chmod a= file.txt
x=`grep value file.txt | awk '{print $2*2}'`
echo "should never be printed"
この例では、2番目のgrepコマンドはゼロ以外の終了状態で失敗しますが、サブシェルはまだ状態0で完了するawkコマンドを実行します。したがって、サブシェル全体の終了状態はゼロであり、スクリプトは引き続き実行されます。
ウェブ検索では set -e の制限事項についていくつかの記事が表示されますが、誰でもきれいな回避策をお勧めできますか?
答え1
x=`grep value file.txt | awk '{print $2*2}'`
2番目のgrepコマンドはゼロ以外の終了状態で失敗しますが、サブシェルはまだawkコマンドを実行します。
これは実際にはサブシェルとは関係がなく、むしろパイプがどのように機能するかに関するものです。シェルブート両方パイプラインの(すべての)コマンドは同時に実行されるため、右側のコマンドが開始されるまで左側の終了状態もわかりません。
はい、デフォルトではパイプの終了状態は一番右のコマンドの終了状態です。通常、これはパイプを完成させ、一番右のコマンドがすべての入力を読み取らずに終了し、最も左のコマンドが現在閉じているパイプにさらに書き込もうとするとSIGPIPE信号によって終了するために便利です。
残りのデータには実際に興味がないので、これはバグではありません。次の場合にのみ確認することを検討してくださいzcat file.gz | grep -q xyz
。xyz
どこかにデータから少なくとも一度は。
とにかく、彼らがコメントで述べたように、最もset -o pipefail
右側にあるものを得るために多くのシェル(Bash、ksh、zsh、Busybox、少なくとも)を使用します。0以外終了ステータスは、パイプライン全体の終了ステータスを決定します。
ただし、grep
エラーが発生した場合だけでなく、一致する行がない場合でもエラー状態が返されることに注意してください。これがバグと見なされたくない場合は、より多くのことを行う必要があります。
awk
この特別な場合は、パターンマッチングを実行することもできます(例:)x=$(awk '/value/ {print $2 * 2}' < file.txt)
。ファイルを読み取れない場合は、エラーで終了する必要があります。