如何在Perl中运行外部命令并捕获其输出?

时间:2010-03-17 10:34:10

标签: perl stdout stderr

我是Perl的新手,想知道在以下场景中运行外部命令(称之为prg)的方法:

  1. 运行prg,仅获取stdout
  2. 运行prg,仅获取stderr
  3. 运行prg,分别获取stdoutstderr

4 个答案:

答案 0 :(得分:27)

您可以使用背景来执行外部程序并捕获其stdoutstderr

默认情况下,反引号会丢弃stderr并仅返回外部程序的stdout。所以

$output = `cmd`;

将捕获程序cmd的stdout并丢弃stderr

要仅捕获stderr,您可以将shell的文件描述符用作:

$output = `cmd 2>&1 1>/dev/null`;

要捕获stdoutstderr,您可以执行以下操作:

$output = `cmd 2>&1`;

使用上述内容,您将无法将stderrstdout区分开来。从stdout分离stderr可以将两者重定向到单独的文件并阅读文件:

`cmd 1>stdout.txt 2>stderr.txt`;

答案 1 :(得分:10)

答案 2 :(得分:8)

在大多数情况下,您可以使用qx//运算符(或反引号)。它插入字符串并使用shell执行它们,因此您可以使用重定向。

  • 捕获命令的STDOUT(STDERR不受影响):

    $output = `cmd`;
    
  • 一起捕获命令的STDERR和STDOUT:

    $output = `cmd 2>&1`;
    
  • 捕获命令的STDERR但丢弃其STDOUT(这里的排序很重要):

    $output = `cmd 2>&1 1>/dev/null`;
    
  • 交换命令的STDOUT和STDERR以捕获STDERR,但让STDOUT退出旧STDERR:

    $output = `cmd 3>&1 1>&2 2>&3 3>&-`;
    
  • 要分别读取命令的STDOUT和STDERR,最简单的方法是将它们分别重定向到文件,然后在程序完成时从这些文件中读取:

    system("program args 1>program.stdout 2>program.stderr");
    

答案 3 :(得分:1)

请注意上面的Eugene的回答(无法评论他的回答),交换SDTOUT和STDERR的语法在Unixes上有效(我猜是像Unixen的shell,例如ksh或bash),但无效。 Windows CMD下(错误:3>& was unexpected at this time.)。

在Windows上的Windows CMD和Perl下,适当的语法是:

perl -e "$r=qx{nslookup 255.255.255.255 2>&1 1>&3 3>&2};

请注意,命令:

nslookup 255.255.255.255

将在STDOUT上产生(类似):

Server:  mymodem.lan
Address:  fd37:c01e:a880::1

和在STDERR上:

*** mymodem.lan can't find 255.255.255.255: Non-existent domain

您可以测试此语法是否适用于以下CMD / Perl语法:

第一:

perl -e "$r=qx{nslookup 255.255.255.255 2>&1 1>&3 3>&2}; $r=~s/[\n\r]//eg; print qq{on STDOUT qx result=[$r]};"

您得到:Server: mymodem.lan Address: fd37:c01e:a880::1 on STDOUT qx result=[*** mymodem.lan can't find 255.255.255.255: Non-existent domain]

然后

perl -e "$r=qx{nslookup 255.255.255.255 2>&1 1>&3 3>&2}; $r=~s/[\n\r]//eg; print STDOUT qq{on STDOUT qx result=[$r]};" 2>&1 1>NUL:

您得到:Server: mymodem.lan Address: fd37:c01e:a880::1

QED [fr:CQFD]

请注意,不可能同时将stderr和stdout作为qx或backticks命令的返回字符串。如果您确定您所产生的命令返回的错误文本长度为N行,您仍然可以像Eugene和其他人所描述的那样将STDERR重定向到STDOUT,但是将您的qx返回的文本捕获到数组中而不是作为标量字符串。 STDERR流将在STDOUT之前之前返回到数组,以便数组的前N行是SDTERR行。喜欢:

@r=qx{nslookup 255.255.255.255 2>&1};
$r[0] is "*** mymodem.lan can't find 255.255.255.255: Non-existent domain"

但是,当然,您必须确保STDERR上有 个错误文本,并且严格按N行(存储在@r[0..N-1]中)。如果没有,唯一的解决方案就是使用如上所述的临时文件。