
シェル スクリプトで、名前付きパイプを使用して外部プロセス X の stdin に書き込み、別の名前付きパイプからの stdout/stderr を現在の端末に送信したいと考えています。
外部プロセス X は PIPEIN 経由で stdin を受信し、stdout/stderr を PIPEOUT に送信しています。
tail -f $(tail -F PIPEOUT) & # (1) this is completely wrong, need help here
for i; do
echo "${i}" > PIPEIN # send stdin to X
done
echo "[stdin end]" > PIPEIN # signal that we are done writing (there might be a better way lol)
上記のスクリプトでは、プロセス X はすでに開始されており、しばらく実行されています。しかし、上記のスクリプトを実行するときに、X に stdin を送信し、PIPEOUT を使用してプロセス X から stdout を読み取ります。
私が上記でやろうとしているのは、stdin を X に送信する前に PIPEOUT の読み取りを設定して、X の stdout/stderr をすべてキャプチャできるようにすることです。問題は、バックグラウンド プロセス (PIPEOUT から読み取るための tail または cat) を実行して、その stdio を現在の端末に送信する方法がわからないことです。
私が何を言っているのか分かる人はいますか。間違っていなければ、(1) というラベルの付いた行を修正し、PIPEOUT から読み取り、その stdio を現在の端末/tty に何らかの方法で送信できるバックグラウンドでの読み取りを設定する必要があります。
答え1
何をしたいのかよく分かりませんtail -f $(tail -F PIPEOUT) &
。tail -f
の結果である tail -F
、これは通常決して終了しません。私の想定では、どれだけ時間がかかっても、パイプを通過するすべてのものを出力したいはずです。
justの問題はtail -f
、何かを出力する前にファイルの終わりを見つけなければならないことですが、パイプではそれは起こりません。tail
代わりに明確な開始点を与える-n +x
、開始する行を選択します (先頭から 1 からインデックス付けされます)。tail -n 1 -f foo
から取得できるすべてのものを表示しますfoo
。
tr 'a-z' 'A-Z' < PIPEIN > PIPEOUT & # for example
tail -n +1 -f PIPEOUT &
for i in a b c d ; do
echo $i > PIPEIN
done
echo "[stdin end]" > PIPEIN
ただし、行を書き込んだ後に foo が閉じられることに注意してくださいecho > foo
。反対側のコマンドは、これを適切に処理する必要があります。この例が人工的で、実際の入力がどこか別の場所から来ている場合は、これを無視できます。
また、プロセスはtail
決して終了しない— パイプから何かが来るかもしれないと期待し続けます。シェルのジョブ制御などを使って、明示的に終了させる必要があります。終了したことを示す出力パターンがある場合は、retail
(「正規表現による末尾」)役に立つ —retail -n +1 -f -u REGEX PIPEOUT
一致する行がREGEX
現れると終了します。(免責事項として、私はretail
数年前にまさにこの目的で書きました)
答え2
書き込み用に PIPEIN を 1 回だけ開くと、2 秒の遅延があってもプログラムは終了します。
mkfifo PIPEIN PIPEOUT
tr 'a-z' 'A-Z' < PIPEIN > PIPEOUT & # for example
tail -n +1 -f PIPEOUT &
(
for i in a b c d ; do
echo $i
done
sleep 2
echo "[stdin end]"
) > PIPEIN
fifo を複数回開くと、fifo のリーダーによって閉じられていると認識される可能性があり、別のリーダーが fifo から読み取るまでライターはハングします。
したがって、PIPEIN を一度だけ開くのが安全策です。そうしないと、プログラムがロックしてしまう可能性があります。