
コマンド出力にプレフィックスを付けますが、戻り値を確認できる以下のコードより良い方法はありますか?
command > "$tmpfile" 2>&1
ret=$?
sed 's/^/ | /' "$tmpfile"
if [[ ! "$ret" -eq 0 ]]; then
rm "$tmpfile"
exit 1
fi
答え1
他の一部のシェルでは、bash
このオプションを使用できますpipefail
。このオプションを使用すると、パイプの終了状態は、一番右のコンポーネントの終了状態ではなく、失敗した一番右のコンポーネントの終了状態になります。
(set -o pipefail; cmd | sed 's/^/ | /') || exit
別のオプションは、パイプを使用するのではなく、stdoutをプロセス置換にリダイレクトすることです。
cmd > >(sed 's/^/ | /') || exit
この場合、バックグラウンドで開始されて待機しませんが、sed
次のコマンドが実行されるまで書き込みが完了していない可能性があります。
特に、パイプラインの各コンポーネントの終了状態を記録する特別な配列(zshにはそれに対応する配列があります)がbash
あります。$PIPESTATUS
$pipestatus
cmd | sed 's/^/ | /'; ret=${PIPESTATUS[0]}
[ "$ret" -eq 0 ] || exit "$ret"
POSIXlyでは、次のことができます。
{
ret=$(
exec 4>&1
{
cmd 3>&- 4>&-
echo "$?" >&4
} | sed 's/^/ | /' >&3 3>&- 4>&-
)
} 3>&1
[ "$ret" -eq 0 ] || exit "$ret"
ヘルパー機能を使用できます。
prefix() (
prefix=$1; shift
exit "$(
exec 4>&1
{
"$@" 3>&- 4>&-
echo "$?" >&4 3>&- 4>&-
} | PREFIX=$prefix awk '{print ENVIRON["PREFIX"] $0}' >&3 3>&- 4>&-
)"
) 3>&1
prefix ' | ' cmd
awk
(任意のプレフィックスを使用できるように切り替えられます。