
特定のストリーム(次の例ではstdin)のEOFを読み込むと自動的に終了するプログラムがあります。
ここで、名前付きパイプを作成し、プログラムのstdinをそれに接続するシェルスクリプトを作成したいと思います。次に、スクリプトはパイプに書き込みます。数回echo
およびcat
(および終了時に自動的に EOF を生成するその他のツール) を使用します。私が直面している問題は、最初の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
答え1
他の人が指摘しているように、パイプのリーダーは、ライターが残っていないと 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 を受け取る) ことに注意してください。利便性の他に、スクリプトが何らかの理由で早期に終了した場合にも、これによりある種の安全性が確保されます。
答え2
最後のライターがなくなると、パイプは EOF を受け取ります。これを回避するには、ライター (書き込み用にパイプを開いているが、実際には何も書き込まないプロセス) が常に存在するようにします。EOF を送信するには、その予備のライターをなくします。
mkfifo P
while sleep 1; do :; done >P &
P_writer_pid=$!
send_eof_to_P () {
kill $P_writer_pid
}
答え3
プログラムには、「終了する時間です」を意味する EOF と、「ライターは終了しましたが、他のユーザーからの入力がまだある可能性があります」を意味する EOF を区別する方法はありません。
プログラムの動作を変更できる場合は、無限ループで読み取り (1 回の反復は EOF まで続きます) を行い、「終了する時間」を意味する特定のコマンド文字列を送信します。その文字列を送信することが、send_eof
質問のコマンドのタスクになります。
別のオプション:
( echo some stuff; cat more_stuff.txt ) >P
または
{ echo some stuff; cat more_stuff.txt; } >P