$ PIPESTATUSをtee(またはpee)コマンドで使用できますか?

$ PIPESTATUSをtee(またはpee)コマンドで使用できますか?

私のbashスクリプトはパイプラインを頻繁に使用し、パイプラインのどの段階でエラーが発生するかを知りたいと思います。これらの断片の基本構造は次のとおりです。

#!/bin/bash

ProduceCommand 2>/dev/null | ConsumeCommand >/dev/null 2>&1
PipeErrors=("${PIPESTATUS[@]}")
[[ "${PipeErrors[0]}" -eq '0' ]] || { HandleErrorInProduceCommand; }
[[ "${PipeErrors[1]}" -eq '0' ]] || { HandleErrorInConsumeCommand; }

teeさて、(うーんと最初に)またはどちらかが利用可能であれば、それは良いような状況にありますpee。しかし、$PIPESTATUSこのコマンドを使用するとどうなりますか?例えば:

#!/bin/bash

ProduceCommand 2>/dev/null | tee >(ConsumeCommand1) >(ConsumeCommand2) >/dev/null 2>&1
PipeErrors=("${PIPESTATUS[@]}")

または

#!/bin/bash

ProduceCommand 2>/dev/null | pee ConsumeCommand1 ConsumeCommand2 2>/dev/null
PipeErrors=("${PIPESTATUS[@]}")

私はどちらの場合も${PipeErrors[0]}エラー状態を反映していると思いますProduceCommand。さらに、${PipeErrors[1]}それぞれがエラー状態を反映するか、エラー状態であると仮定するのが論理的である。teepee

しかし、これは少なくとも2つの理解問題を引き起こす。

  1. teeまたはのエラー状態(戻り値)は何ですかpee?マニュアルページでこれの正確な説明が見つかりませんでした。消費コマンドの1つが失敗した場合は、ハードコードされたエラー状態を返しますか、それとも消費コマンドのエラー状態(たとえばssh)を渡しますか?前者の場合、どの消費者命令が原因であるかをどのように知ることができますか?後者の場合、どのエラー状態が渡されますか?まず失敗するコマンドでしょうか?

  2. AFAIK、bash、またはteeコマンドpee自体は、それぞれ内部でパイプ(fifos)を使用して出力をProduceCommand消費コマンドにインポートします。これは、(最初​​とこの場合のみ)受信側がパイプ自体であるパイプがあることを意味します。これは上記のサンプルコードには影響しません$PipeErrorsが、実際にはわかりません。

誰かがこれを説明できますか?

ベストアンサー1

エラー状態(戻り値)とは何ですか?tee

すべてのデータをすべての出力ファイルにコピーできる場合は0、コピーできない場合は> 0です。より仕様。これGNU coreutilsの実装tee書き込み中にエラーを無視する追加のオプションがあります。管路(実装に使用したものと同じ>(...)):

$ seq 1024 | tee >(false) >/dev/null; echo $?
141
$ seq 1024 | tee -p >(false) >/dev/null; echo $?
0

わかるオプションはありませんどの出力が失敗しました(存在する場合)[1]。


>(..)しかし、あなたの質問は、プロセスオーバーライドで実行されるコマンドの終了状態がどのように反映されるかPIPESTATUSについてです。可能何らかの方法で実装されますPIPESTATUS

正解はいいえ

まず、パイプラインコマンドではなくバックグラウンドコマンド>(...)に似ていることに注意してください。次のスニペットから:... &...|...

... | tee >(cmd ...) | ...; echo ${PIPESTATUS[@]}

cmd実行すると完了する保証はありませんecho ${PIPESTATUS[@]}

しかし、いくつかの限られた場合を除いて、それらはそれらから得られず、...&それらwaitからそれらの状態も取得できないので、まったく同じではありません。$!いいえtee他の外部コマンドとの使用を含める:

$ bash -c 'echo 1 | tee >(sleep 2; sed s/1/2/); wait; echo DONE'
1
DONE
$
<after two seconds>
2

ご覧のとおり、メインシェルteeとメインシェルは、コマンドが実行される前に完了します>(...)

[1]同様のコマンドがpee出力「サブコマンド」自体を実行しています(そして完了するのを待っています)。できるより賢明に、サブコマンドが失敗した終了状態を反映します(たとえば、最初のサブコマンドのビット1の設定、2番目のサブコマンドのビット2の設定など、最大8つのサブコマンドの設定)。しかし、そうしませんでした。

おすすめ記事