10

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?

1
  • 2
    You might want to take a look at Net-SNMP. With that you'll have full error control and needn't worry about redirecting output someplace else. Commented Dec 5, 2011 at 11:40

4 Answers 4

15

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.
Sign up to request clarification or add additional context in comments.

Comments

8

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

5 Comments

Well I don't have to handle errors (because they're more like warnings to me) so that solution may be suitable for me. I'm gonna try that right now :)
It doesnt work :( error.dat is empty and errors are still raised on the command line :(
I don't know why it shouldn't work. If it's creating the file, then the shell is working as expected. I can only suppose that snmpwalk is outputting the error by some other mechanism than printing on STDERR, but I don't know what. I was going to say, if you don't want the output anyway, '2>/dev/null', but if the error.dat case doesn't work, nor will that, probably.
That's really strange, in fact I never had this problem before. I looked at snmpget help and there are some additional log options that might help but they don't seem to work.
it is not "the only way" you can redirect strerr to stdout. 2>&1
5

In the Perl FAQ you have different options depending how do you want to proceed:

http://perldoc.perl.org/perlfaq8.html#How-can-I-capture-STDERR-from-an-external-command%3f

2 Comments

Backticks and open() read only the STDOUT of your command. So it looks like I can't capture STDERR, I must use Open3, thanks for the answer btw!
while this faq is correct, it is unnecessarily complicated and IMO incomplete. While the basic Perl language makes this difficult, there are modules which can help, see my answer for examples using Capture::Tiny
0

IO::CaptureOutput

is a very convenient wrapper for what you want to do.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.