专业编程基础技术教程

网站首页 > 基础教程 正文

什么是缓冲?(什么是缓冲间)

ccvgpt 2024-07-21 17:40:07 基础教程 26 ℃

大多数标准的Unix命令在非交互式使用时会进行输出缓冲。这意味着它们不会立即写入每个字符(甚至每一行),而是在打印任何内容之前先收集一定数量的字符(通常是4千字节)。在上面的例子中,grep命令会对其输出进行缓冲,因此awk只会以较大的块方式获取输入。

缓冲大大提高了I/O操作的效率,并且通常以一种对用户不可见的方式进行。从交互式终端会话中简单的tail -f命令可以正常工作,但是当命令是复杂管道的一部分时,该命令可能无法识别到最终输出需要(接近)实时。幸运的是,有几种技术可用于控制I/O缓冲行为。

什么是缓冲?(什么是缓冲间)

关于缓冲最重要的一点是,它是由写入者来执行的,而不是读取者。

消除不必要的命令

在问题中,我们有一个管道命令tail -f logfile | grep 'foo bar' | awk ...(实际的AWK命令未指定)。如果我们只运行tail -f logfile,就没有任何问题,因为tail -f从不对其输出进行缓冲。如果我们以交互方式运行tail -f logfile | grep 'foo bar',也没有问题,因为如果grep的标准输出是终端,则它不会对其输出进行缓冲。然而,如果grep的输出被传送到其他位置(比如一个AWK命令),它会开始进行缓冲以提高效率。

在这个特定的例子中,grep实际上是多余的。我们可以将其删除,并让AWK在执行其他操作的同时执行过滤:

tail -f logfile | awk '/foo bar/ ...'

在其他情况下,这种合并可能不可行。但是你应该始终首先寻找最简单的解决方案。

您的命令可能已支持非缓冲输出

某些程序提供了专门针对这类问题的特殊命令行选项:

awk(GNU awk、nawk、busybox awk、mawk)

使用fflush()函数。它将在POSIX Issue 8中定义

awk(mawk)

-W interactive

find(GNU)

使用带有\c转义字符的-printf

grep(例如GNU版本2.5.1)

--line-buffered

jq

--unbuffered

python

-u

sed(例如GNU版本4.0.6)

-u,--unbuffered

tcpdump、tethereal

-l

为了使整个管道能够(接近)实时运行,每个写入管道的命令都需要被告知禁用缓冲。如果管道中的最后一个命令正在写入终端,则通常不需要特殊考虑。

在C应用程序中禁用缓冲

如果缓冲应用程序是用C编写的,并且要么是你自己的程序,要么是你可以修改源代码的程序,你可以使用以下代码禁用缓冲:

setvbuf(stdout, NULL, _IONBF, 0);

通常情况下,你可以将此代码添加到main()函数的顶部,但如果应用程序关闭并重新打开stdout?,或者在之后显式调用了setvbuf()?,则可能需要更谨慎地处理。

unbuffer

expect软件包中有一个名为unbuffer的程序,可以有效地使其他程序始终表现得像它们正在进行交互(这通常会禁用缓冲)。下面是一个简单的示例:

tail -f logfile | unbuffer grep 'foo bar' | awk ...

expect和unbuffer不是标准的POSIX工具,但它们可能已经安装在你的系统上。

stdbuf

GNU coreutils的最新版本(从7.5开始)附带了一个名为stdbuf的实用程序,可以用于“取消缓冲”命令的标准输出,以下是我们示例的基本用法:

tail -f logfile | stdbuf -oL grep 'foo bar' | awk ...

上面的代码中,-oL?表示将stdout设置为行缓冲;你甚至可以使用-o0?完全禁用缓冲。有关详细信息,请参阅手册页。

stdbuf不是标准的POSIX工具,但它可能已经安装在你的系统上(如果你使用最新的GNU/Linux发行版,它可能已经存在)。

less

如果你只想突出显示搜索词,而不是过滤掉不匹配的行,你可以使用less程序而不是带过滤的tail -f命令:

less program.log
  • 在less中,使用“/”命令(类似于vi中的搜索)开始搜索。或者在启动less时使用-p?选项指定模式。
  • 这将突出显示搜索词的所有实例。
  • 现在将less设置为“follow”模式,默认情况下绑定到shift+f键。
  • 你将得到指定文件的未过滤的尾部,其中搜索词被突出显示。

“Follow”模式可以通过中断停止,你的系统上可能是control+c键。/?命令接受正则表达式,因此你可以执行诸如突出显示包含搜索词的整行之类的操作。有关详细信息,请参阅man less。

coproc

如果你使用的是ksh或Bash 4.0+,并且你在使用tail -f时想要实现的功能可能受益于使用coproc和fflush()创建一个协程。请注意,coproc本身并不解决缓冲问题(实际上它容易出现缓冲问题,因此提到了fflush)。这里之所以提到coproc,是因为每当有人试图持续监视和响应仍在增长的文件(或管道)时,他们可能正在尝试从协程中获益的某些操作。


如果您觉得文章内容对你有一点帮助可以关注我,我在头条平台会持续分享更多实用的shell技巧和最佳实践,如果想系统的快速学习shell的各种高阶用法和生产环境避坑指南可以看看《shell脚本编程最佳实践》专栏,专栏里有更多的实用小技巧和脚本代码分享。

Tags:

最近发表
标签列表