阻止自动EOF到命名管道,并在需要时发送EOF


12

我有一个程序,在读取给定流中的EOF时会自动退出(在以下情况下为stdin)。
现在,我想制作一个Shell脚本,该脚本创建一个命名管道并将程序的stdin连接到它。然后,脚本使用和(以及其他工具退出时自动生成EOF)多次写入管道。我面临的问题是,当第一个操作完成时,它会向管道发送EOF并退出程序。如果我使用类似的东西,那么我打算退出程序时无法发送EOF。我正在研究一种平衡的解决方案,但无济于事。 我已经找到了如何防止EOF以及如何手动发送EOF的方法,但是我无法将它们结合在一起。有什么提示吗? echocatechotail -f

#!/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

Answers:


13

正如其他人指出的那样,一旦没有作家,管道的读者就会收到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
exec 3>P会导致重击,为什么呢?

@Wang不应该。如果是这样,那么您可能没有执行与问题中的POC代码相同的操作。我可以认为它将阻止的唯一原因是,如果您改为执行exec 2>P,并且打开了跟踪模式(set -x),则bash会向管道写入数据,但是没有读取器,因此它阻塞了等待一些东西要读。
Patrick

1
@Wang @Patrick确实也exec 3>P挂在我的机器上。这是因为没有从中读取进程P。因此,解决方案是交换行exec 3>Pprogram < P &(添加与号,以便程序在后台运行)。
Macieksk

2

当最后一个作者离开时,管道将收到EOF。为避免这种情况,请确保始终有一个writer(一个进程,该进程打开了用于写入的管道,但实际上并未写入任何内容)。要发送EOF,请让该备用作者离开。

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

0

该程序无法区分表示“该退出了”的EOF和表示“一个作家已经完成,但可能会有其他人的更多输入”的EOF。

如果您具有修改程序行为的能力,则可以无限循环进行读取(一个迭代持续到EOF为止),然后向其发送一个特定的命令字符串,该字符串表示“退出时间”。发送该字符串将是send_eof您问题中命令的任务。

另外一个选项:

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

要么

{ echo some stuff; cat more_stuff.txt; } >P
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.