web-dev-qa-db-ja.com

名前付きパイプへの自動EOFを防止し、必要に応じてEOFを送信します

与えられたストリーム(以下の場合はstdin)でEOFを読み取ると自動的に終了するプログラムがあります。
次に、名前付きパイプを作成してプログラムの標準入力をそれに接続するシェルスクリプトを作成します。次に、スクリプトはパイプに書き込みます数回echoおよびcat(およびEOFが自動的に生成される他のツールを使用してexit)。私が直面している問題は、最初のechoが完了すると、EOF=をパイプに送信し、プログラムを終了させることです。 tail -fその後、プログラムを終了するつもりでEOF=を送信できません。バランスの取れたソリューションを研究していますが、役に立ちません。
EOFを防ぐ方法と手動でEOFを送信する方法の両方を見つけましたが、それらを組み合わせることができません。ヒントはありますか?

#!/bin/sh
mkfifo P
program < P & : # Run in background
# < P tail -n +1 -f | program
echo some stuff > P # Prevent EOF?
cat more_stuff.txt > P # Prevent EOF?
send_eof > P # How can I do this?
# fg
12
iBug

他の人が示したように、パイプのリーダーは、ライターがなくなるとEOFを受け取ります。したがって、解決策は、常に1つのライターが開いたままにすることです。そのライターには何かを送信するには、開いたままにします。

シェルスクリプトを使用しているので、最も簡単な解決策は、書き込み用にパイプを開くようにシェルに指示することです。そして、終わったらそれを閉じます。

#!/bin/sh
mkfifo P
exec 3>P # open file descriptor 3 writing to the pipe
program < P
# < P tail -n +1 -f | program
echo some stuff > P
cat more_stuff.txt > P
exec 3>&- # close file descriptor 3

最後の行を省略した場合、スクリプトが終了すると、ファイル記述子3は自動的に閉じられます(したがって、リーダーはEOFを受け取ります)。便利さはさておき、スクリプトが何らかの理由で早期に終了した場合でも、これは一種の安全性を提供します。

13
Patrick

パイプは、EOFを受け取ります。これは、最後のライターがなくなると発生します。これを回避するには、ライター(パイプが書き込み用に開いているが実際には何も書き込まないプロセス)が常に存在するようにします。 )EOFを送信するには、その予備のライターを削除します。

mkfifo P
while sleep 1; do :; done >P &
P_writer_pid=$!
send_eof_to_P () {
  kill $P_writer_pid
}

プログラムがEOFこれは「やめる時間だ」という意味ですが、EOFは「ライターが完成したという意味ですが、他の誰かからのより多くの入力があるかもしれません。」.

プログラムの動作を変更する機能がある場合は、無限ループ(1回の反復がEOFまで続く)で読み取りを行い、「終了時間」を意味する特定のコマンド文字列を送信します。その文字列を送信することは、send_eofコマンドで質問してください。

別のオプション:

( echo some stuff; cat more_stuff.txt ) >P

または

{ echo some stuff; cat more_stuff.txt; } >P
0
Kusalananda