如果从标准输入中读取,冲洗标准输出似乎无效

我有以下脚本:

#!/usr/bin/perl -w
use strict;
$| = 1;
foreach (1..5) {
    print $_ . "\r";
    sleep 1;
}
print "\n";

这表现出预期的效果:数字1,2,3,4,5在控制台上相互覆盖。

$ ./loop.pl | hexdump -C
00000000  31 0d 32 0d 33 0d 34 0d  35 0d 0a                 |1.2.3.4.5..|

但是,另一个脚本(旨在显示隐藏长时间运行的程序的大型输出,例如:long_running_program | tee output | ./progr

#!/usr/bin/perl -w
use strict;
$| = 1;
while (<>) {
    chomp;
    print $_ . "\r";
}
print "\n";
输入重定向后,

会产生不同的行为:

 perl -wle 'foreach (1..5) { print $_; sleep 1 }' | ./progr.pl

五秒钟没有看到输出,然后可以看到“ 5”。但是hexdump显示相同的输出(五秒钟后)

$ perl -wle 'foreach (1..5) { print $_; sleep 1 }' | ./progr.pl | hexdump.exe -C
00000000  31 0d 32 0d 33 0d 34 0d  35 0d 0a                 |1.2.3.4.5..|

这不是Perl特有的。以下C代码

for (int i = 0; i < 6; ++i) {
    printf("%d\r",i);
    fflush(stdout);
    sleep(1);
}
puts("\n");

显示数字彼此覆盖,但是

#define SIZE (256 * 1024)
char buffer[SIZE];
int line = 0;
while (fgets(buffer,SIZE,stdin)) {
    printf("%d\r",++line);
    fflush(stdout);
}
puts("\n");

在管道末端时,仅在输入耗尽后才显示输出。

甚至没有

setvbuf(stdout,NULL,_IONBF,0);

似乎有帮助。

我通过SSH连接到远程Linux(RHEL6)系统并在Cygwin本地进行了所有尝试。

(通过@Fredrik和@usr的更正进行编辑)

wgzwang 回答:如果从标准输入中读取,冲洗标准输出似乎无效

您正在寻找错误的程序。您在管道的第二个程序中关闭了输出缓冲,但没有关闭第一个程序。


STDOUT如果连接到端子则为行缓冲,否则为块缓冲。

行缓冲:输出换行时刷新。

块缓冲:当缓冲区已满时刷新。

由于管道(输入生成器)的第一个程序的STDOUT连接到管道,因此其输出将进行块缓冲。而且由于缓冲区足够大,可以容纳程序的全部输出,因此输入生成器在退出之前实际上不会输出任何东西。

更改

perl -wle 'foreach (1..5) { print $_; sleep 1 }' | ./progr.pl

perl -wle '$| = 1; foreach (1..5) { print $_; sleep 1 }' | ./progr.pl

但是,如果您无法控制该程序怎么办?有时您可以使用unbuffer哄骗其他程序来关闭缓冲。

unbuffer perl -wle 'foreach (1..5) { print $_; sleep 1 }' | ./progr.pl
,

在大多数示例中,您正在管道输出仅包含回车符(直到程序结束并打印换行符(对于C版本为两个换行符))到每次读取换行符终止行的程序。当然,直到第一个程序结束,您才不会看到第二个程序的输出-它在换行符或文件末尾等待返回第一行。


perl -wle 'foreach (1..5) { print $_; sleep 1 }' | ./progr.pl情况下,是的,多亏了-l选项,换行了,但是输出被缓冲了,因为它是到管道的,并且progr.pl看不到任何输入直到第一部分完成。在循环之前的开始处添加$|=1;,您会得到不同的结果。

本文链接:https://www.f2er.com/3134754.html

大家都在问