継続的インテグレーションのために、シェルスクリプト内でコマンドを呼び出したいのですが。終了ステータス0は成功、それ以外の場合は失敗を意味します。複数のコマンドを実行し、そのうちの1つからエラーが発生した場合に失敗するラッパースクリプトを作成しています。
ただし、コマンドの1つ(サードパーティソフトウェア)は、「事実上の」終了ステータス!= 1に準拠していません。ただし、障害が発生した場合は、エラーをstderrに出力します。
other-command
スイッチが原因でmycommand
と-e
の両方が終了ステータス!= 0で失敗する場合は、現在のラッパースクリプトが正常に機能しているはずです。
#!/bin/bash -ex
mycommand --some-argument /some/path/to/file
other-command --other-argument /some/other/file
Stderrに出力されているものをチェックするにはどうすればよいですか(メインスクリプトを失敗させるため)?これが私が試したものです:
Stderrをサブシェルstdinにリダイレクトします。例:
mycommand 2> >(if grep .; then echo NOK; else echo OK; fi)
これは正常に動作するようですが、ここでメインシェルを制御して終了することはできません。つまり、exit 1
はメインプログラムを終了しません。また、サブシェルの外部で変数を制御してその結果を伝播することもできません。名前付きパイプなどを本当に作成する必要がありますか?
この答え のような追加のファイル記述子を設定します。
本当にエレガントに見えません。
いくつかの「要件」:
したがって、印刷された出力を保持したまま、クリーンでないステータスでのみ終了するラッパーのように動作する必要があります。
Stderrで何かをチェックするためにもっとエレガントなものが存在することを期待していました。バシズムは受け入れられる。
あなたができる(POSIXly):
if { cmd 2>&1 >&3 3>&- | grep '^' >&2; } 3>&1; then
echo there was some output on stderr
fi
または、元の終了ステータスがゼロ以外の場合にそれを保持するには:
fail_if_stderr() (
rc=$({
("$@" 2>&1 >&3 3>&- 4>&-; echo "$?" >&4) |
grep '^' >&2 3>&- 4>&-
} 4>&1)
err=$?
[ "$rc" -eq 0 ] || exit "$rc"
[ "$err" -ne 0 ] || exit 125
) 3>&1
終了コードの使用125
は、コマンドが0の終了ステータスで戻るが、いくつかのエラー出力を生成した場合。
として使用する:
fail_if_stderr cmd its args || echo "Failed with $?"
# output "NOK" if standard error has any output; "OK" otherwise:
errlog=$(mktemp)
somecommand 1>> "$stdlog" 2> "$errlog"
if [[ -s "$errlog" ]]; then
# File exists and has a size greater than zero
echo "NOK"
else
echo "OK"
fi
# Done parsing standard error; tack it to the regular log
cat "$errlog" >> "$stdlog"
rm -f "$errlog"