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

问题描述 投票:17回答:4

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

  1. 运行prg,只获得它的stdout
  2. 运行prg,只获得它的stderr
  3. 运行prg,分别得到它的stdoutstderr
perl stdout stderr
4个回答
27
投票

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

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

$output = `cmd`;

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

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

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

要捕获stdoutstderr,您可以:

$output = `cmd 2>&1`;

使用上面你将无法区分stderrstdout。要将stdoutstderr分开,可以将两者重定向到单独的文件并读取文件:

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

10
投票

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");

1
投票

请注意Eugene的答案(不能评论他的答案),就在上面,交换SDTOUT和STDERR的语法在Unix上是有效的(类似于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或反引号命令的返回字符串。如果您确定生成的命令返回的错误文本的长度为N行,您仍然可以将STDERR重定向到STDOUT,就像Eugene和其他人描述的那样,但是将数组中的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]中)。如果没有,唯一的解决方案是使用如上所述的临时文件。

© www.soinside.com 2019 - 2024. All rights reserved.