最简单的方法是通过管道访问设置无阻塞输出的程序。这是简单的perl oneliner(您可以将其保存为泄漏缓冲区),它可以这样做:
所以你a | b
变成:
a | perl -MFcntl -e \
'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (<STDIN>) { print }' | b
所做的是读取输入并写入输出(与相同cat(1)
),但是输出是非阻塞的-这意味着如果写入失败,它将返回错误并丢失数据,但是该过程将继续输入的下一行,因为我们方便地忽略了输入错误。流程可以根据需要进行行缓冲,但是请参见下面的警告。
您可以使用以下示例进行测试:
seq 1 500000 | perl -w -MFcntl -e \
'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (<STDIN>) { print }' | \
while read a; do echo $a; done > output
您将获得output
丢失行的文件(确切的输出取决于外壳的速度等),如下所示:
12768
12769
12770
12771
12772
12773
127775610
75611
75612
75613
您会看到shell在哪里丢失了行12773
,但是又出现了一个异常-perl没有足够的缓冲区,12774\n
但是这样做了,1277
所以它只写了这样-因此下一个数字75610
不在行的开头开始,因此很少丑陋。
可以通过以下方式来改进:通过perl检测何时写入未完全成功,然后在忽略新行的同时刷新剩余的行,但这会使perl脚本更加复杂,因此作为练习有兴趣的读者:)
更新(针对二进制文件):
如果您不处理换行符终止的行(如日志文件或类似文件),则需要稍微更改命令,否则perl将消耗大量内存(取决于换行符在输入中出现的频率):
perl -w -MFcntl -e 'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (read STDIN, $_, 4096) { print }'
它也将对二进制文件也正常工作(不消耗额外的内存)。
Update2-更好的文本文件输出:
避免使用输出缓冲区(syswrite
而不是print
):
seq 1 500000 | perl -w -MFcntl -e \
'fcntl STDOUT,F_SETFL,O_NONBLOCK; while (<STDIN>) { syswrite STDOUT,$_ }' | \
while read a; do echo $a; done > output
似乎为我解决了“合并线”的问题:
12766
12767
12768
16384
16385
16386
(注:可以使用perl -ne '$c++; next if $c==$_; print "$c $_"; $c=$_' output
oneliner 验证在哪些行上剪切了输出)