How do I receive command output immediately? - perl

I'm using perl back-ticks syntax to run some commands.
I would like the output of the command to written to a file and also printed out to stdout.
I can accomplish the first by adding a > at the end of my back-ticked string, but I do not know hot to make the output be printed as soon as it is generated. If I do something like
print `command`;
the output is printed only after command finished executing.
Thanks,
Dave

You cannot do it with the backticks, as they return to the Perl program only when the execution has finished.
So,
print `command1; command2; command3`;
will wait until command3 finishes to output anything.
You should use a pipe instead of backticks to be able to get output immediately:
open (my $cmds, "-|", "command1; command2; command3");
while (<$cmds>) {
print;
}
close $cmds;
After you've done this, you then have to see if you want or not buffering (depending on how immediate you want the output to be): Suffering from buffering?
To print and store the output, you can open() a file to write the output to:
open (my $cmds, "-|", "command1; command2; command3");
open (my $outfile, ">", "file.txt");
while (<$cmds>) {
print;
print $outfile $_;
}
close $cmds;
close $outfile;

Related

Opening a pipe and delays in parsing the output in Perl

I am trying to do a fairly simple process using Perl. A snippet of the code:
open(FH,"<command> |") or die "Could not run command .. $!\n";
print "After open\n";
while(<FH>)
{
print "I am inside loop\n";
<process..something>
}
I am seeing some inexplicable delays when the while() is called. I see the open took 9-10ms to run ( which is within range ), however I do see 200 - 250ms delay between the messages "After open" and "I am inside loop".
Has anyone seen anything like this before ? Any help would be appreciated.
Thanks
Rajib
This is almost certainly because the output from <command> is buffered until either the buffer fills up or the process terminates
You can probably get around this using unbuffer, which pretends to the command that it is outputting to a terminal
Try using this instead
open my $fh, '-|', 'unbuffer <command>' or die "Could not run command: $!\n";

Perl - Show progress during execution of a system() command

I am trying to write a Perl CGI which executes an RKHunter scan. While executing the comman, I would like to show something to indicate progress instead of the actual output which is to be redirected to another file. The code thus far is:
open(my $quik_rk, '-|', 'rkhunter', '--enable', '"known_rkts"') or print "ERROR RUNNING QUICK ROOTKIT CHECK!!";
while(<$quik_rk>)
{ print ".";
}
print "\n";
close($quik_rk);
This doesn't show any output and I am presented with a blank screen while waiting for execution to complete. All the dots are printed to the screen together instead of one-by-one., Moreover, when I use the following to redirect, the command doesn't execute at all:
open(my $quik_rk, '-|', 'rkhunter', '--enable', '"known_rkts"', '>>', '/path/to/file') or print "ERROR RUNNING QUICK ROOTKIT CHECK!!";
How can I fix this in such a way that the verbose output is redirected to a file and only a .... steadily progresses on the screen?
$|=1;
At the beginning of your script.
This turns autoflush on so every print actually prints instead of waiting for a newline before flushing the buffer.
Also see: http://perldoc.perl.org/perlvar.html#Variables-related-to-filehandles

Perl: how can I capture output in a variable in the same time showing it in standard output?

I started working on a perl script and I'm calling external rsync application to do a backup.
I want to capture the output of the rsync action and I'm using this format:
print "Starting backup. Please wait...\n";
my #output = `rsync -avut /home /media/drive/`;
At this point, the script is running as is supposed to, but the action of the rsync is captured into my array and I can't see the progress. Is there a way to capture the output as above, but also show it in my console?
The backticks capture STDOUT and places it in your array.
If you want to see STDOUT as well as capture it in a variable, you could use open().
I think something like this might work?
my $output;
print "Starting backup. Please wait...\n";
open(RSYNC, "-|", "rsync -avut /home /media/drive")
or die "Can't exec rsync : $!";
while(<RSYNC>)
{
print $_;
$output .= $_;
}
close(RSYNC);
something like this might do the trick
use strict;
my $fh;
open $fh, "find /|"; #don't forget to check it opens!!
while (<$fh>){
chomp;
print "here--$_\n";
}
You can take a look at this related question. The accepted answer suggests using Capture::Tiny.

Perl's print function: print to last filehandle?

I am confused by this bit of Perldoc:
If FILEHANDLE is omitted, prints to the last selected (see select) output handle.
http://perldoc.perl.org/functions/print.html
It seems to say that a naked print statement, after writing to a filehandle, will print to that filehandle. I wrote a script to test this...
#!/usr/bin/perl
open (FILE, '>', 'PrintTest.txt') or die $!;
print FILE "Hello world!\n";
print "Hello.... hello? hello world!\n";
close FILE;
But the test shows otherwise.
$ perl PrintTest.pl
Hello.... hello? hello world!
We're writing to STDOUT here, not FILE, which is probably the most sensible result, but seems contrary to that line of Perldoc quoted above. Perhaps I am misunderstanding what "last selected output handle" means? That is the only way I can think to explain this :-p
Thanks in advance ~ ktm
It seems to say that a naked print statement, after writing to a filehandle, will print to that filehandle.
No, it says it will print to the last selected handle, not the last handle to which you printed. It proceeds to instruct you to read this page to see how to do it.
open (FILE, '>', 'PrintTest.txt') or die $!;
print FILE "Hello world!\n";
select(FILE); <----- Missing
print "Hello.... hello? hello world!\n";
close FILE;
I believe a SELECT statement is required to change the default handle from stdout to another. Then, the selected handle remains in use until changed.

Redirecting STDOUT of a pipe in Perl

I feel as though there should be a simple way to do this, but searching around gives me no good leads. I just want to open() a pipe to an application, write some data to it, and have the output of the subprocess sent to the STDOUT of the calling script.
open(my $foo, '|-', '/path/to/foo');
print $foo 'input'; # Should behave equivalently to "print 'output'"
close($foo);
Is there a simple way to do this, or have I hit upon one of the many "can't get there from here" moments in Perl?
The subprocess will inherit STDOUT automatically. This works for me:
open(my $f, "|-", "cat");
print $f "hi\n";
If you are not really closing the pipe immediately the problem might be on the other end: STDOUT is line-buffered by default, so you see print "hello world\n" immediately. The pipe to your subprocess will be block-buffered by default, so you may actually be waiting for the data from your perl script to reach the other program:
open(my $f, "|-", "cat");
print $f "hi\n";
sleep(10);
close($f); # or exit
# now output appears
Try adding select $f; $| = 1 (or I think the more modern way is $f->autoflush(1))