无法将多个 shell 语句重定向到命名管道

Posted

技术标签:

【中文标题】无法将多个 shell 语句重定向到命名管道【英文标题】:Can't redirect multiple shell statements to named pipe 【发布时间】:2013-11-12 20:17:55 【问题描述】:

观察当我一个接一个地发出两个命令时会发生什么,而不是在一行中,用分号分隔:

制作管道并启动电影:

$ mkfifo pipe1
$ tail -f /dev/null > pipe1 &
$ cat pipe1 | omxplayer /path/to/video.mp4

退出试验 1:

$ echo -n q > pipe1; # Exits movie, but omxplayer hangs
$ echo > pipe1; # Completes exit process

退出试验 2:

$ echo -n q > pipe1; echo > pipe1 # Does nothing

退出试验 3:

$ echo -n q > pipe1; sleep 1; echo > pipe1 # Works just like trial 1

有人可以解释为什么试验 2 什么都不做。另外,有没有更好的方法通过命名管道发出退出命令,不需要两个echo 语句?

【问题讨论】:

如果您的目标是运行两个输出到 FIFO 的命令而不关闭它们之间的 FIFO,则可以轻松解决: foo; bar; >pipe。但是,从您描述的行为来看,听起来 omxplayer 可能要求您关闭 FIFO。 ...顺便说一下,echo -n 不是 POSIX 标准(echo -E 也不是)。最好使用printf 【参考方案1】:

如果 fifo 上的最后一个写入器死了,而读取器检查了 fifo,它会看到一个文件结尾。如果在阅读器检查之前再次有新的写入器,则阅读器看不到文件结尾。我猜你的阅读器(omxplayer)会检查文件结尾。

从读者omxplayer的角度来说:它看到了

    "q" EOF ... <LF> EOF "q" (EOF 可能没有被omxplayer 看到) <LF> EOF "q" EOF ... <LF> EOF

会发生什么完全取决于omxplayer 的处理方式,而不是你自己、操作系统或你的 shell 搞砸了。

【讨论】:

谢谢,但我不太理解你的意思:last writer, fifo dies, new writer before reader checks , 文件结束...基本上所有内容 =P 您的echo 命令写入管道,即fifo。由于它们是由您的 shell 作为子进程运行的单独命令,因此它们终止(死亡)。读者是omxplayer,他正在检查fifo中是否有可用数据。 哦,您的意思是输入的输入速度可能快于它们的处理速度? 不是真的;我想这只是omxplayer 如何处理其输入的问题。我猜该程序涉及一些超时,它会根据您输入的时间改变其行为。【参考方案2】:

我怀疑以某种方式涉及缓冲。 (1) 和 (3) 都在 q 和换行之间提供了一段相对较长的时间,停止电影但直到读完一整行才退出。在 (2) 中,q 和换行非常接近,以至于 omxplayer 可能只是忽略了整个字符串。 echo q > pipe1(类似于(2),但更快)有什么作用?

【讨论】:

echo q > pipe1 不起作用(因此为什么我转向echo -n q > pipe1...基本上我在破解我不理解的东西) 是的,我也不清楚omxplayer 对标准输入做了什么,你必须阻止echo 发送换行符。尝试cat -u pipe1 | omxplayer /path/to/video.mp4,这将禁用缓冲,并且可能在您按下q 后允许omxplayer 退出,而无需后续echo > pipe1 哦,我认为原因是 omxplayer 只支持一次击键(即你按q 而不是qENTER 没有缓冲,至少在用户空间中没有,因为涉及多个写入进程。【参考方案3】:

omxplayer 对其(命令)输入有点挑剔。它不喜欢以换行符 '\n' 终止的命令(例如 q )。 将换行符作为命令的一部分 ('q''\n') 会错误地处理它,从而导致未知命令(而只有 'q' 作为有效命令存在)。因此,当echo-ing 命令到omxplayer 时,-n 选项是必需的。

除了omxplayer 的这种“错误处理”之外,在使用cat pipe1 | cat 时可以看到相同的行为。在杀死 second cat 之后,它是最后一个(或第一个跟随)echo 终止 first cat

【讨论】:

请不要在回答中提问。为他们提出一个新问题,或获得足够的声誉以先发表评论。

以上是关于无法将多个 shell 语句重定向到命名管道的主要内容,如果未能解决你的问题,请参考以下文章

将命名管道输入重定向到文件

键盘输入错误地重定向到命名管道读取

将子进程的 stdout 和 stderr 重定向到两个命名管道(然后从它们读回)

/bin/sh:如何从 &3 重定向到命名管道?

SIGPIPE 如何影响命名管道中的作者?

如何使用 Unix(或 Windows)中的(最好是未命名的)管道将一个进程的标准输出发送到多个进程?