将 EOF 发送到命名管道 - 清理/干燥 fifo

Ale*_*lls 7 pipe shell-script tail fifo

如果我有一些从命名管道读取的随机进程:

tail -f MYNAMEDPIPED 
cat MYNAMEDPIPE | someOtherProc
Run Code Online (Sandbox Code Playgroud)

在其他地方,我可以按名称处理 MYNAMEDPIPED。是否有一种安全干净的方法可以通过删除 MYNAMEDPIPED 或以某种方式“使其变干”来停止尾部进程?

换句话说

MYNAMEDPIPED.noMoreDataIsComingThroughSoPleaseStopTailingThis()
Run Code Online (Sandbox Code Playgroud)

:)

从其中一条评论来看,它说将 EOF 发送到 MYNAMEDPIPE。但我无法弄清楚如何做到这一点。

这显示了我面临的困难:

http://comp.os.linux.questions.narkive.com/2AW9g5yn/sending-an-eof-to-a-named-pipe

mos*_*svy 8

EOF正如一些顽固的都市传说所暗示的那样,它既不是一个角色也不是一个“事件”,也不能通过管道发送,或“喂”到它的写作结束。

在管道/fifo 的读取端生成 an的唯一方法EOF(即导致其read(2)上的a返回 0)是关闭所有打开的句柄到其写入端。

如果所有在写入模式下打开命名管道的进程和所有继承文件描述符的子进程fork()都被终止 [1],这将自动发生。

如果read(2)管道以读/写模式打开,则命名管道上的 a不可能返回 0,例如。和

exec 7<>/path/to/fifo
Run Code Online (Sandbox Code Playgroud)

因为在这种情况下,管道的两端只有一个文件描述符/句柄,关闭写端也将关闭读端,使得 a 不可能read(2)返回 0(管道不支持任何类型的半关闭,就像套接字一样与shutdown(2))。

[1] 以及所有通过SCM_RIGHTSunix 套接字上的辅助消息接收到文件描述符的进程。


请注意,tail -f 根据定义EOF,无论它读取的文件是常规文件还是特殊文件,都不会终止于。杀死所有持有文件描述符打开句柄的进程的一种方法是fuser(1)

tail -f /path/to/fifo
...
> /path/to/fifo  # let any blocking open(2) through
fuser -TERM -k /path/to/fifo
Run Code Online (Sandbox Code Playgroud)

请注意,这也会杀死(无意中)/path/to/fifo从其父母那里继承了一个开放句柄的进程。


ste*_*fan 1

您无法 \xe2\x80\x9c 发送 EOF\xe2\x80\x9d。根本没有 \xe2\x80\x9cEOF 字符\xe2\x80\x9d 会通过管道。

\n\n

通常,Linux 程序在阻塞模式下使用 (2) 从文件描述符读取数据read,用接收到的数据填充缓冲区,并返回读取的字符数。当read返回 0 时,即已读取 0 个字节,大多数程序将其解释为文件结束。

\n\n

程序可以使用 (2) 在缓冲区满之前刷新管道的一侧fsync。在这种情况下,即使缓冲区为空,读取器read也会立即返回,并返回 0 作为读取字节数。

\n\n

您可以通过运行cat、输入一些字符(不回车)并按 Ctrl-D (这会导致终端刷新)来观察这一点。此时,cat将打印键入的字符。再次按下 Ctrl-D,cat'sread将返回 0 字节,假设cat已到达文件末尾。由于使用了行缓冲,因此cat当您按回车键时也会打印其输入。

\n

  • 这个答案在最后一段中描述的内容仅发生在 ttys 上,而不发生在管道上;即使管道的缓冲区为空,管道写入端的“fsync()”也不会导致读取端的“read()”返回 0。 (2认同)