左コマンドが多数の出力を生成するときにダッシュパイプ"left | right"で左コマンドの終了状態を確認する方法

左コマンドが多数の出力を生成するときにダッシュパイプ

変数 "PIPESTATUS" がdash.simple にあるようです。一人で実行左のコマンドは非常に大きな出力を生成するので、動作しません。私はこれを行うためにfifoを使います。

#!/bin/dash
mkfifo command1 command2
dash -c "cat ./content;code=\${?};echo \${code} > command1 &" | dash -c "md5sum;code=\${?};echo \${code} > command2 &"
echo "$(cat ./command1)" "$(cat ./command2)"

しかし、なぜ壊れたのかわかりませんか?

ベストアンサー1

名前付きパイプを使用して両方のプロセスを手動で接続できます。逆順で開始すると、左が前景で実行され、通常どおり$?終了状態が得られます。

#!/bin/sh
dir=$(mktemp -d)
mkfifo "$dir/p"
cat < "$dir/p" > /dev/null &
( echo foo; exit 12; ) > "$dir/p"
echo "exit status: left: $?"
rm -r "$dir"

または、両方が必要な場合は、バックグラウンドプロセスのPIDを取得し、$!終了waitステータスを取得します。

#!/bin/sh
dir=$(mktemp -d)
mkfifo "$dir/p"
( echo foo; exit 12; ) > "$dir/p" &          # left-hand side
pidleft=$!
( cat; exit 34; ) < "$dir/p" > /dev/null &   # right-hand side
pidright=$!
wait "$pidleft"; exitleft=$?
wait "$pidright"; exitright=$?
echo "exit status: left: $exitleft right: $exitright"
rm -r "$dir"

パイプの2番目の部分は前景にそのまま残すことができます。私はただ対称的にしたかっただけです。


終了ステータスをファイルに保存し、そこからインポートすることもできます。

#/bin/sh
( somecmd; echo "$?" > exit1 ) | ( cat; echo "$?" > exit2)
echo "exit status: left: $(cat exit1) right: $(cat exit2)"

終了状態はほんの数バイトしかないので、ここでは名前付きパイプはあまり使われていないと思います。シェルは、exit12行目で読み取りを試みる前にパイプが完了するのを待ちます。exit2

名前付きパイプを使用するには、読み取り側が開くまでパイプブロックに書き込むため、パイプをバックグラウンドに配置する必要があります。

#/bin/sh
mkfifo exit1 exit2
( somecmd; echo "$?" > exit1 ) | ( cat; echo "$?" > exit2) &
echo "exit status: left: $(cat exit1) right: $(cat exit2)"

ただし、catパイプを読み取るsが何らかの理由で実行されない場合、パイプを書き込むサブシェルはバックグラウンドで無期限にブロックされます。

おすすめ記事