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

发布于 08-25 20:05 字数 250 浏览 10 评论 0原文

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

  1. 运行 prg,获取其 仅标准输出。
  2. 运行prg,仅获取其stderr
  3. 运行prg,分别获取其stdoutstderr

I'm new to Perl and want to know of a way to run an external command (call it prg) in the following scenarios:

  1. Run prg, get its stdout only.
  2. Run prg, get its stderr only.
  3. Run prg, get its stdout and stderr, separately.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

祁梦2024-09-01 20:05:59

在大多数情况下,您可以使用 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("程序参数 1>program.stdout 2>program.stderr");
    

In most cases you can use the qx// operator (or backticks). It interpolates strings and executes them with the shell, so you can use redirections.

  • To capture a command's STDOUT (STDERR is unaffected):

    $output = `cmd`;
    
  • To capture a command's STDERR and STDOUT together:

    $output = `cmd 2>&1`;
    
  • To capture a command's STDERR but discard its STDOUT (ordering is important here):

    $output = `cmd 2>&1 1>/dev/null`;
    
  • To exchange a command's STDOUT and STDERR in order to capture the STDERR but leave its STDOUT to come out the old STDERR:

    $output = `cmd 3>&1 1>&2 2>&3 3>&-`;
    
  • To read both a command's STDOUT and its STDERR separately, it's easiest to redirect them separately to files, and then read from those files when the program is done:

    system("program args 1>program.stdout 2>program.stderr");
    
心清如水2024-09-01 20:05:59

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

攒眉千度2024-09-01 20:05:59

请注意上面 Eugene 的答案(无法评论他的答案),交换 SDTOUT 和 STDERR 的语法在 Unix 上有效(类似 Unixen 的 shell,如 ksh 或我猜的 bash),但在 Windows CMD 下无效(错误:3>&此时是意外的。)。

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

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

请注意,该命令:

nslookup 255.255.255.255

: 上生成(类似的内容)

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

将在 STDOUT:和 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]};"

您会得到: 服务器:mymodem.lan
地址:fd37:c01e:a880::1
在 STDOUT qx result=[*** mymodem.lan 找不到 255.255.255.255: 不存在的域]

然后

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:

你得到:服务器:mymodem.lan
地址:fd37:c01e:a880::1

QED [fr:CQFD]

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

Beware about the answer of Eugene (can't comment on his answer), just above, that the syntax to exchange SDTOUT and STDERR is valid on Unixes (Unixen-like shells such as ksh, or bash I guess) but not under Windows CMD (error: 3>& was unexpected at this time.).

The appropriate syntax under Windows CMD and Perl on Windows is:

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

Note that the command:

nslookup 255.255.255.255

will produce (something like) on STDOUT:

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

and on STDERR:

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

You can test that this syntax works with the following CMD/Perl syntax:

First:

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]};"

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

Then

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:

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

QED [fr:CQFD]

Note that it is not possible to get BOTH stderr and stdout as returned string for a qx or backticks command. If you know for sure that the err text returned by your spawned command is of length N lines, you can still redirect STDERR to STDOUT like describe by Eugene and others but capture your qx returned text in an array instead of as scalar string. The STDERR flow will be returned into the array before the STDOUT so that the N first lines of your array are the SDTERR lines. Like:

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

But of course you must be sure that there is an err text on STDERR and of strictly N lines (stored in @r[0..N-1]). If not, the only solution is using temp files as described above.

愛上了2024-09-01 20:05:58

您可以使用 backtics 来执行外部程序并捕获其 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`;

You can use the backtics to execute your external program and capture its stdout and stderr.

By default the backticks discard the stderr and return only the stdout of the external program.So

$output = `cmd`;

Will capture the stdout of the program cmd and discard stderr.

To capture only stderr you can use the shell's file descriptors as:

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

To capture both stdout and stderr you can do:

$output = `cmd 2>&1`;

Using the above you'll not be able to differenciate stderr from stdout. To separte stdout from stderr can redirect both to a separate file and read the files:

`cmd 1>stdout.txt 2>stderr.txt`;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文