Reputation: 973
I don't know if this is possible but I'm working on sending the output of a command over sockets so it will be shown on both the client and server computer while the command is running. When I try to use backticks the output isn't saved into the variable until the command completes which is bad for when I run a command that takes a long time.
Question: Is there a way to scan the output on a line by line basis by say spawning another process and having it "watch" a variable?
Edit: This is what I tried with open
open DATA, "pause |" or die "Failed: $!";
while( defined(my $line = <DATA>)){
chomp($line);
print "$line\n";
}
I would like the output to be shown before the command completes.
Upvotes: 3
Views: 342
Reputation: 385917
You have the right approach.
my @cmd = ( 'perl', '-e', '$|=1; for (1..5) { print "$_\n"; sleep 1; }' );
open(my $pipe, '-|', @cmd)
or die("Can't launch child: $!\n");
while (defined( my $line = <$pipe> )) {
chomp($line);
print "<$line>\n";
}
When writing to STDOUT, most programs flush their output when a newline is encountered when STDOUT is a terminal ("line buffering"). Most programs fall back to block outputting chunks of 4 KiB or 8 KiB when STDOUT isn't a terminal ("block buffering"). That's why I had to use $|=1;
in the child program in the example above.
Programs that behave as described can be fooled into using line buffering using pseudo-terminal instead of a pipe.
my @cmd = ( 'unbuffer', 'perl', '-e', 'for (1..5) { print "$_\n"; sleep 1; }' );
open(my $pipe, '-|', @cmd)
or die("Can't launch child: $!\n");
while (defined( my $line = <$pipe> )) {
chomp($line);
print "<$line>\n";
}
IPC::Run provides a native method of creating pseudo-terminals.
use IPC::Run qw( run );
my @cmd = ( 'perl', '-e', 'for (1..5) { print "$_\n"; sleep 1; }' );
my $buf = '';
run(\@cmd, '>pty>', sub {
$buf .= $_[0];
while ($buf =~ s/^(.*)\r\n//) {
print "<$1>\n";
}
});
Upvotes: 6