
私は何かが間違っているときにエラーメッセージを印刷しますが、それに応じて終了ステータスを設定しないプログラムを使用しています。終了ステータスは常に 0 で、成功を示します。シェルスクリプトでこのプログラムを実行し、エラーメッセージが表示されたら、スクリプトがプログラムに失敗するように指示できるように、ゼロ以外の終了ステータスを取得したいと思います。
エラーメッセージは、一致が見つかったかどうかに応じて終了ステータスを一致させ設定できる予測可能なパターンに従い、grep
プログラムgrep
の出力をここにパイプし、grep
結果を無効にして目的の!
終了ステータスを取得できます。
問題は、パイプで接続するとgrep
できないことです。バラよりプログラムの出力はgrep
消費されたため、もはや存在しません。どういうわけか出力からエラーメッセージを検索したいのですが、エラーに加えて他の重要なメッセージがあるので、出力も正常に表示したいと思います。残念ながら、grep
すべての入力、一致する行、一致しない行を渡すオプションはありません。
私が見つけた一つの方法最大作品は次のとおりです
! my_program | tee /dev/stderr | grep -q "error message"
これはプログラムの出力をstderrに入れますが、grep
stderrにもコピーするので、私が見ることができるようにリダイレクトされません。私のスクリプトのstdoutとstderrの両方がターミナルに送信されても大丈夫です(したがって、どちらがメッセージを受け取るかは問題ではありません)。ただし、stdoutとstderrが別の場所にリダイレクトされると、メッセージが終了する可能性があります。間違った場所。
POSIXシェルとGNUツールを使用してプログラムの標準出力および/または標準エラーストリームをスキャンし、それに応じて終了ステータスを設定し、両方のストリームを通常のターゲットに到達させるbash
(簡潔な)方法はありますか?grep
(my_program
stderrではなくstdoutにエラーメッセージを書き込むので、stdoutストリームのみをスキャンできるソリューションは理想的ではありませんが、問題ありません。違いがある場合はCentOS 7でこれを行っています。)
答え1
...grepなどのツールを使用してプログラムのstdoutストリームおよび/またはstderrストリームをスキャンし、それに応じて終了ステータスを設定し、同時に2つのストリームを通常のターゲットに到達させる(簡潔な)方法はありますか?
...my_programは、標準エラーではなく標準出力にエラーメッセージを記録します。標準出力ストリームのみをスキャンするソリューションは問題ありません。しかし、理想的ではありません。
私の解決策は答えた。勇敢な上部です。
最も簡単な方法は次のことだと思いますawk
。
myprogram |
awk 'BEGIN {status = 0} /error message/ {status = 1} 1; END {exit(status)}'
このawk
コマンドは、入力したすべてをそのまま出力しますが、最終的に終了する状態は、「エラーメッセージ」が入力の一部かどうかによって異なります。
簡潔なバージョン(短い変数名):
myprogram | awk 'BEGIN{s=0} /error message/{s=1} 1; END{exit(s)}'
答え2
$MSG
以下は、stdout / stderrからエラーメッセージをgrepし、エラーメッセージが表示されたときにプログラムを停止/停止しないいくつかのライナーです。
# grep on stdout, do not stop early
my_program | awk -v s="$MSG" '$0~s{r=1} 1; END{exit(r)}'
# grep on stdout, do stop early
my_program | awk -v s="$MSG" '$0~s{exit(1)} 1'
# grep on stderr, do not stop early
{ my_program 2>&1 >&3 | awk -v s="$MSG" '$0~s{r=1} 1; END{exit(r)}' >&2; } 3>&1
# grep on stderr, do stop early
{ my_program 2>&1 >&3 | awk -v s="$MSG" '$0~s{exit(1)} 1' >&2; } 3>&1
メモ:
誰にでも対応:アプリのストリームは着信を確認しながらデフォルトの
grep
ttyステータスを失います。これは、ストリームに書き込まれる方法に影響を与える可能性があります。たとえば、カーソル位置を制御できないと仮定することができ、回転している進行状況バーが印刷されない可能性があります。my_program
awk
my_program
両方について:stdoutとstderrはマージされず、通常どおり互いに独立してリダイレクトできます。
誰にでも:元の終了コード
my_program
は完全に無視されます。他の簡単なオプションは次のとおりです。my_program
エラーまたはエラーメッセージで終了した場合は、エラーで終了します。。この動作を得るには、pipefail
パイプラインを実行しているBashシェルでそれを有効にする必要があります。たとえば、(set -o pipefail; my_program | awk -v s="$MSG" '$0~s{exit(1)} 1')
stderrのgrep操作の場合:上記の簡単なコマンドラインでは、ファイル記述子3が使用されていないとします。これは一般的にできることです。これらの仮定を避けるために、Bash が使用されないように保証されるファイル記述子を割り当てるようにすることができます。
bash -c 'exec {fd}>&1; { my_program 2>&1 >&${fd} | awk -v s="$MSG" '\''$0~s{exit(1)} 1'\'' >&2; } ${fd}>&1'
答え3
2つの端末を並べてみてください。最初のシェルウィンドウで:
tail -F /tmp/xyzzy
2番目は正確にtmpファイルに対してのみ行うことです。
my_program | tee /tmp/xyzzy | grep -q "error message"
その順番で始めてください。
一時ファイルを頻繁に削除するか、新しい名前を選択する必要があるため、不正ですが機能します。
後で追加するには...次のようにしてみてください。
my_program | tee /tmp/xyzzy ; grep -q "error message" /tmp/xyzzy
シーケンスの終了状態は grep の終了状態です。これはあなたが望むものとは反対です、ため息。だから否定してください。
my_program | tee /tmp/xyzzy ; ! grep -q "error message" /tmp/xyzzy
答え4
baz()
出力するデモ機能の作成「金持ち」到着標準出力そして「バー」到着標準エラー:
baz() { echo foo ; echo bar >& 2 ; }
簡単な場合は実行してみてgrep foo
ください。標準出力、およびgrep bar
情報標準エラー:
{ baz 2>&1 1>&3 | grep bar 1>&2 ; } 3>&1 | grep foo
同じ内容が使用されますが、tee
出力はgrep
まったく使用されていないようです。
{ baz 2>&1 1>&3 | tee /dev/stderr | grep -q bar ; } 3>&1 | \
{ tee /dev/stderr | grep -q foo ; } 2>&1
grep -q bar
「BEEP!」を印刷して条件を追加してください。標準エラーもしバー発見する:
{ baz 2>&1 1>&3 | tee /dev/stderr | grep -q bar && echo "BEEP!" >&2 ; } 3>&1 | \
{ tee /dev/stderr | grep -q foo ; } 2>&1
最後の2行の出力は次のようになります。
foo
bar
BEEP!