2011-12-05 22 views
7

假设我想用反引号从脚本运行一个外部程序,同时我想捕获STDOUT和STDERR,但是需要两个不同的变量。我怎样才能做到这一点?对于istance如果我运行此脚本...如何在Perl中使用反引号在两个不同的变量中捕获STDOUT和STDERR

my $cmd = `snmpwalk -v $version -c $community $hostname $oid`; 

...如果没有错误一切工作得很好,但如果命令引发错误将在命令行上打印这个错误,我不希望这种事情发生。我也想捕捉错误。屏幕上无需打印任何内容。有任何想法吗?

+2

你可能想看看[网-SNMP](http://search.cpan.org/~dtown/Net-SNMP-v6.0.1/)。这样你就可以完全控制错误,不用担心重定向输出。 –

回答

5

在Perl中常见问题你有这取决于你怎么想进行不同的选择:

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

+0

*反向和打开()只读你的命令的标准输出*所以它看起来像我不能捕获STDERR,我必须使用Open3,谢谢为答案btw! – raz3r

+1

虽然这个常见问题是正确的,它是unnec复杂和IMO不完整。虽然基本的Perl语言使这很困难,但有些模块可以提供帮助,使用['Capture :: Tiny'](http://p3rl.org/Capture::Tiny)查看我的答案。 –

8

与反引号做到这一点的唯一方法是重定向到shell命令中的文件:

my $cmd = `snmpwalk -v $version -c $community $hostname $oid 2>error.dat`; 

如果你想捕捉的STDERR您的脚本中,你需要IPC::Open3,而不是反引号

+0

好吧,我不必处理错误(因为它们更像是对我的警告),因此解决方案可能适合我。我现在要试试:) – raz3r

+0

它不工作:(error.dat是空的,错误仍在命令行上提出:( – raz3r

+1

我不知道为什么它不应该工作。如果它正在创建文件,那么shell就像预期的一样工作了,我只能假设snmpwalk通过其他机制输出错误,而不是在STDERR上打印,但我不知道是什么,如果你不想输出无论如何,'2>/dev/null',但如果error.dat的情况下不起作用,也可能不会。 –

11

您不需要一直到open3,这个IIRC只适用于需要读取和写入外部命令时,甚至还有其他方法。

对于你的问题,我建议使用Capture::Tiny,它可以捕捉(或甚至发球)的STDOUT和STDERR从其块内运行的任何东西。例如,根据您的问题:

#!/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"); 
}; 

再比如考虑这个功能代码:

#!/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"; 

这只是给了我:

STDOUT: 
hello 
Mon Dec 19 23:59:06 CST 2011 
STDERR: 
Arg1! at ./test.pl line 11. 
相关问题