我是Perl的新手,想知道在以下场景中运行外部命令(称之为prg
)的方法:
prg
,仅获取stdout
。prg
,仅获取stderr
。prg
,分别获取stdout
和stderr
。答案 0 :(得分:27)
您可以使用背景来执行外部程序并捕获其stdout
和stderr
。
默认情况下,反引号会丢弃stderr
并仅返回外部程序的stdout
。所以
$output = `cmd`;
将捕获程序cmd的stdout
并丢弃stderr
。
要仅捕获stderr
,您可以将shell的文件描述符用作:
$output = `cmd 2>&1 1>/dev/null`;
要捕获stdout
和stderr
,您可以执行以下操作:
$output = `cmd 2>&1`;
使用上述内容,您将无法将stderr
与stdout
区分开来。从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]
中)。如果没有,唯一的解决方案就是使用如上所述的临时文件。