我有一个程序,在读取给定流中的 EOF 时自动退出(在以下情况下为 stdin )。
现在我想制作一个 shell 脚本,它创建一个命名管道并将程序的标准输入连接到它。然后脚本写入管道几次使用echo
and 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。因此,解决方案是确保始终有一位作家将其打开。该作者不必发送任何内容,只需将其打开即可。
由于您使用的是 shell 脚本,最简单的解决方案是告诉 shell 打开管道进行写入。然后完成后关闭它。
#!/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 表示“编写完成,但可能还有其他人的输入”。
如果您有能力修改程序的行为,则可以在无限循环中进行读取(一次迭代持续到 EOF),并向其发送一个表示“退出时间”的特定命令字符串。发送该字符串将是send_eof
您问题中的命令的任务。
另外一个选择:
( echo some stuff; cat more_stuff.txt ) >P
或者
{ echo some stuff; cat more_stuff.txt; } >P