26

我是 Perl 新手,想知道prg在以下情况下运行外部命令(调用它)的方法:

  1. 运行prg,得到它的stdout唯一。
  2. 运行prg,得到它的stderr唯一。
  3. 分别运行prg,得到它的stdoutand stderr
4

4 回答 4

38

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

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

$output = `cmd`;

将捕获stdout程序 cmd 并丢弃stderr

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

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

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

$output = `cmd 2>&1`;

使用上述内容,您将无法stderr区分stdout. 要分离stdout可以stderr将两者重定向到单独的文件并读取文件:

`cmd 1>stdout.txt 2>stderr.txt`;
于 2010-03-17T10:42:40.180 回答
10

在大多数情况下,您可以使用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");
    
于 2010-03-17T10:49:53.103 回答
10

您可以使用IPC::Open3IPC::Run。另外,请阅读如何perlfaq8的外部命令中捕获 STDERR 。

于 2010-03-17T11:05:54.710 回答
2

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

Windows CMD 和 Windows 上的 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]

请注意,对于 qx 或反引号命令,不可能同时获取 stderr 和 stdout 作为返回字符串。如果您确定生成的命令返回的 err 文本长度为 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]如果没有,唯一的解决方案是使用上述临时文件。

于 2019-03-13T20:40:23.103 回答