Capture the output of Perl's 'system()'

That's what backticks are for. From perldoc perlfaq8:

Why can't I get the output of a command with system()?

You're confusing the purpose of system() and backticks (``). system() runs a command and returns exit status information (as a 16 bit value: the low 7 bits are the signal the process died from, if any, and the high 8 bits are the actual exit value). Backticks (``) run a command and return what it sent to STDOUT.

my $exit_status   = system("mail-users");
my $output_string = `ls`;

See perldoc perlop for more details.


IPC::Run is my favourite module for this kind of task. Very powerful and flexible, and also trivially simple for small cases.

use IPC::Run 'run';

run [ "command", "arguments", "here" ], ">", \my $stdout;

# Now $stdout contains output

Simply use similar to the Bash example:

    $variable=`some_command some args`;

That's all. Notice, you will not see any printings to STDOUT on the output because this is redirected to a variable.

This example is unusable for a command that interact with the user, except when you have prepared answers. For that, you can use something like this using a stack of shell commands:

    $variable=`cat answers.txt|some_command some args`;

Inside the answers.txt file you should prepare all answers for some_command to work properly.

I know this isn't the best way for programming :) But this is the simplest way how to achieve the goal, specially for Bash programmers.

Of course, if the output is bigger (ls with subdirectory), you shouldn't get all output at once. Read the command by the same way as you read a regular file:

open CMD,'-|','your_command some args' or die $@;
my $line;
while (defined($line=<CMD>)) {
    print $line; # Or push @table,$line or do whatever what you want processing line by line
}
close CMD;

An additional extended solution for processing a long command output without extra Bash calling:

my @CommandCall=qw(find / -type d); # Some example single command
my $commandSTDOUT; # File handler
my $pid=open($commandSTDOUT),'-|'); # There will be an implicit fork!
if ($pid) {
    #parent side
    my $singleLine;
    while(defined($singleline=<$commandSTDOUT>)) {
        chomp $line; # Typically we don't need EOL
        do_some_processing_with($line);
    };
    close $commandSTDOUT; # In this place $? will be set for capture
    $exitcode=$? >> 8;
    do_something_with_exit_code($exitcode);
} else {
    # Child side, there you really calls a command
    open STDERR, '>>&', 'STDOUT'; # Redirect stderr to stdout if needed. It works only for child - remember about fork
    exec(@CommandCall); # At this point the child code is overloaded by an external command with parameters
    die "Cannot call @CommandCall"; # Error procedure if the call will fail
}

If you use a procedure like that, you will capture all procedure output, and you can do everything processing line by line. Good luck :)

Tags:

Shell

Perl