非阻塞缓冲命名管道?


20

我正在寻找我怀疑不存在的东西:一个非阻塞的缓冲命名管道(fifo),可从命令行使用。有这样的事吗?

这是用例:假设我有一个进程将在后台长时间运行,并向吐出大量输出stdout。我不是很在意输出,也不想存储它(也许我没有足够的空间),但是我想定期“插入”并跟踪其操作,然后再次退出并留给它做它的工作。因此,我想将其输出重定向到此理论上经过缓冲的,无阻塞的命名管道,然后定期使用它。

所以基本上我想这样开始(10M即缓冲区的大小):

mkmagicfifo magicfifo 10M
spewingprocess > magicfifo &

...并定期进去看看发生了什么...

tail -f magicfifo

... 而不 magicfifo存储所有输出(因此,不是普通文件),也没有在输出被填满且未被点击时阻止喷出过程(因此,不是很普通的命名管道)。

我不认为涉及tailprune将要解决的解决方案(好吧,我可以考虑解决一个涉及的问题tail),因为tail仍然需要将所有数据存储在某个地方(如果我想插手或放弃查看),并且prune必须重写文件,大概(我承认我没有尝试/证明过)破坏了生成所有输出的过程的重定向。

我希望我可以写一些实用程序来做到这一点,但是* nix有 在文件和管道方面很多很棒的方面,我只是忍不住认为它存在并且我只是不知道。

那么:有这样的事情吗?


1
您所描述的是“环形缓冲区”或“圆形缓冲区”。尽管创建起来很简单,但我不知道有任何命令行工具可以维护这种东西。
肖恩·高夫

2
看看stackoverflow.com/questions/7360473/…中的“ Linux非阻塞fifo(按需记录)”中描述的解决方案。

1
像这看起来已经解决了在计算器上: stackoverflow.com/questions/7360473/...
詹姆斯布莱克本

@JamesBlackburn:谢谢!很有意思。
TJ Crowder 2014年

Answers:


16

我认为您正在寻找的是GNU screen。它维护一个缓冲区,以保留一个或多个程序的最后一个屏幕的全部或两个输出,并让您断开连接并稍后再返回。


+1用于提示屏幕。顺便说一句,您可以将其配置为容纳许多“历史记录行”。
舒茨先生,2011年

1
谢谢。您能否举例说明如何将其应用于我在问题中显示的命令?该手册页说它是一个窗口管理器(我认为它们的意思是终端的意思,而不是图形的意思,但仍然)。而且我仍然能够(通过ssh)加入并根据需要退出吗?(例如,远程服务器上的操作。)
TJ Crowder

是的,您可以通过这种方式使用GNU屏幕。您将创建一个新的(可能命名的)会话,在该会话中运行命令,然后断开连接。
TML

2
还有tmuxdtach-在同一类终端复用器/会话管理器应用程序的东西应该能够实现同样的事情。
jw013

5

您可以使用pv,它在管道中提供尽可能多的缓冲。您可以像这样使用它:

sprewingprocess | pv -B 1g > ordinaryfifo &

那将为您spewingprocess和fifo 提供最多1GB的缓冲。大多数Linux发行版都提供pv一个名为的套件,您可以相信或不相信pv


谢谢,但是如果我不读取目标命名管道,那么一旦缓冲区已满就不会阻止该块吗?
TJ Crowder

1
是的,但是您有什么选择?在有限的Universe中,实际上不能有无限的缓冲。
David Schwartz

另一个选择是我在问题中描述的:不存储所有输出。当缓冲区已满时,最旧的东西将被丢弃。
TJ Crowder

嗯,我对此进行了测试,很遗憾,它不能完全正常工作。如果读取fifo的进程停止读取一段时间,则pv会阻止尝试写入fifo,并且由于它不是多线程的,因此也会阻止将数据读取到pv的缓冲区中。因此,pv的缓冲区将仅在读取fifo的过程持续读取的同时继续填充。pv可能能够读取和缓冲某些数据,但是并不能阻止编写器完全阻塞。
Daniel S. Sterling

1

我有同样的问题。这是我的第一个解决方案。首先将输出写入文件,我们在每一行之后都会截断它,以免无限期增长:

spewingprocess | while read line; do echo $line > buffer.txt ; done

然后使用tail读取文件(2> /dev/null删除“文件被截断”错误消息):

tail -f ./buffer.txt 2> /dev/null

这样,缓冲区不会增加,我们可以进行多路复用,例如,根据需要运行任意多个尾巴。但是,这种方法的问题在于,如我们的测试所示,截断速度快于tail读取时,我们可能会丢失数据:

for ((i=0; ; i++)) ; do echo "$i" ; done | while read line; do  echo $line > buffer.txt ; done
tail -f ./buffer.txt 2> /dev/null > log.txt

运行一段时间后,第一行和最后一行是:

$ head -n 1 log.txt
0
$ tail -n 1 log.txt
78783

但是该文件的行较少,因此有些行丢失了:

$ wc log.txt
67087  67087 392819 log.txt

如果您不太在意数据丢失或者当喷出过程不够快而不会丢失数据时,这似乎是一个不错的解决方案。

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.