Let's say I want to run an external program from my script with backticks and at the same time I want to capture both STDOUT and STDERR but in two different variables. How can I do that? For istance if I run this script...
my $cmd = `snmpwalk -v $version -c $community $hostname $oid`;
...if there is no error everything works just fine BUT if the command raise an error this error will be printed on the command line and I don't want that to happen. I want to capture the error as well. Nothing has to be printed on the screen. Any ideas?
You can use Capture::Tiny to capture stdout, stderr or both merged. Show activity on this post. I'm personally a fan of the core module IPC::Open3, though the answer with 2>&1 will get both stderr and stdout in the same stream (and usually good enough).
People knowing shell are familiar with the back-ticks `` that allow us to execute external commands and capture their output. In Perl you can use the back-ticks or the qx operator that does exactly the same, just makes the code more readable.
STDOUT is the Perl filehandle for printing standard output. Unless a filehandle is specified, all standard printed output in Perl will go to the terminal. Because STDOUT is just a global variable, it can be redirected and restored.
You needn't go all the way to open3
, which IIRC is only for when you need to read and write to an external command, and even then there are other methods.
For your problem I suggest using Capture::Tiny
, which can capture (or even tee) the STDOUT and STDERR from anything run inside its block. For example, per your question:
#!/usr/bin/env perl
use strict;
use warnings;
use Capture::Tiny qw/capture/;
...
my ($stdout, $stderr) = capture {
system ( "snmpwalk -v $version -c $community $hostname $oid" );
};
For another example consider this functioning code:
#!/usr/bin/env perl
use strict;
use warnings;
use Capture::Tiny qw/capture/;
my ($stdout, $stderr) = capture {
system ( "echo 'hello'" );
system ( "date" );
warn "Arg1!";
};
print "STDOUT:\n$stdout";
print "STDERR:\n$stderr";
which just gave me:
STDOUT:
hello
Mon Dec 19 23:59:06 CST 2011
STDERR:
Arg1! at ./test.pl line 11.
The only way to do this with backticks is to redirect to a file inside the shell command:
my $cmd = `snmpwalk -v $version -c $community $hostname $oid 2>error.dat`;
If you want to capture the STDERR inside your script, you need IPC::Open3 instead of backticks
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With