I have the following script:
#!/usr/bin/perl -w
use strict;
$| = 1;
foreach (1..5) {
print $_ . "\r";
sleep 1;
}
print "\n";
This behaves as expected: the numbers 1,2,3,4,5 overwrite each other on the console.
$ ./loop.pl | hexdump -C
00000000 31 0d 32 0d 33 0d 34 0d 35 0d 0a |1.2.3.4.5..|
However, a different script (intended to show hide the large output of a long-running program like this: long_running_program | tee output | ./progr)
#!/usr/bin/perl -w
use strict;
$| = 1;
while (<>) {
chomp;
print $_ . "\r";
}
print "\n";
produces different behavior when input is redirected:
perl -wle 'foreach (1..5) { print $_; sleep 1 }' | ./progr.pl
No output is seen for five seconds, then a '5' can be seen. Yet hexdump shows the same output (after five seconds)
$ 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..|
This is not Perl-specific. The following C code
for (int i = 0; i < 6; ++i) {
printf("%d\r", i);
fflush(stdout);
sleep(1);
}
puts("\n");
shows digits overwriting each other, but
#define SIZE (256 * 1024)
char buffer[SIZE];
int line = 0;
while (fgets(buffer, SIZE, stdin)) {
printf("%d\r", ++line);
fflush(stdout);
}
puts("\n");
when at the end of a pipe, only shows output after the input is exhausted.
Not even
setvbuf(stdout, NULL, _IONBF, 0);
appears to help.
I tried all these through an SSH connection to a remote Linux (RHEL6) system, and locally under Cygwin.
(Edited with corrections from @Fredrik and @usr)
stdoutunbuffered (notstdin):setvbuf(stdout, NULL, _IONBF, 0);.setvbuf(stdout, NULL, _IONBF, 0)doesn't help either :(stdbuf -i0 -o0 -e0 long_running_program | tee output | ./progr?