为什么在写入输出后 sed 不立即退出?

Bra*_*Liu 5 sed pv

我在一个大文件上运行 sed,并使用pv实用程序查看它读取输入和写入输出的速度。尽管 pv 显示 sed 在大约 5 秒内读取输入并写入输出,但 sed 又过了 20-30 秒才退出。为什么是这样?

这是我看到的输出:

pv -cN source input.txt | sed "24629045,24629162d" | pv -cN output > output.txt
   source: 2.34GB 0:00:06 [ 388MB/s] [==========================================================================================================>] 100%            
   output: 2.34GB 0:00:05 [ 401MB/s] [              <=>                                                                                                           ]
Run Code Online (Sandbox Code Playgroud)

mik*_*erv 3

有两个原因。首先,你没有告诉它q

考虑:

seq 10 | sed -ne1,5p
Run Code Online (Sandbox Code Playgroud)

在这种情况下,虽然它只p打印输入行的前半部分,但它仍然必须读取其余的输入行直到 EOF。反而:

seq 10|sed 5q
Run Code Online (Sandbox Code Playgroud)

它会立即退出那里。

您还需要处理每个进程之间的延迟。因此,如果pv以 4kb 缓冲,并且sed缓冲 4kb,那么最后一个pv始终落后于输入 8kb。这个数字很可能比这个数字还要高。

您可以尝试-u使用 GNU/BSD/AST 进行切换sed,但这几乎肯定不会对大输入的性能有所帮助。sed如果你用它来调用 GNU,-u它将read()针对输入的每个字节。我没有看过其他人在这种情况下会做什么,但我没有理由相信他们会做任何不同的事情。所有这三个文档-u都表示无缓冲- 这是一个就流而言非常普遍理解的概念。

您可以做的另一件事是使用rite 命令和一个或多个命名的rite-file[s] 显式显示 line-buffersed输出。它仍然会减慢速度,但它可能会比其他选择更好。ww

你可以用任何sed类似的方法来做到这一点:

sed -n 'w outfile'
Run Code Online (Sandbox Code Playgroud)

sedwrite 命令始终是立即的 - 它是无缓冲的输出。并且因为(默认情况下) sed每个行周期应用一次命令,sed所以即使在管道中间也可以轻松用于有效的行缓冲 I/O。这样,至少,你可以让第二个始终保持pv最新状态,sed例如:

pv ... | sed -n '24629045,24629162!w /dev/fd/1' | pv ...
Run Code Online (Sandbox Code Playgroud)

...虽然这假设一个系统提供/dev/fd/[num]链接(也就是说:几乎任何基于 Linux 的系统 - 除了 Android - 以及许多其他系统。如果所述链接的可用性失败,要做同样的事情,您可以显式地创建自己的管道,并将mkfifo其用作最后一个pv的标准输入,并将其命名为sedwrite 文件。