【问题标题】:Getting STDOUT, STDERR, and response code from external *nix command in perl从 perl 中的外部 *nix 命令获取 STDOUT、STDERR 和响应代码
【发布时间】:2012-02-02 17:22:56
【问题描述】:

我想从我的 Perl 脚本中执行一个外部命令,将 stdout 和 stderr 的输出放入我选择的 $variable 中,并将命令的退出代码放入 $? 变量中。

我在perlfaq8 和他们的论坛中查看了解决方案,但它们对我不起作用。奇怪的是,只要退出代码正确,无论如何我不会得到 sdterr 的输出。

我在 Red Hat Linux 5 上使用 Perl 版本 5.8.8。

这是我正在尝试的示例:

my $cmd="less";
my $out=`$cmd 2>&1`;

或

my $out=qx($cmd 2>&1);

或

open(PIPE, "$cmd 2>&1|");

当命令运行成功时,我可以捕获标准输出。

我不想使用额外的捕获模块。如何捕获外部命令的完整结果?

【问题讨论】:

标签: perl stdout stderr


【解决方案1】:

这正是 David Golden 在写 Capture::Tiny 时所面临的挑战。我认为它会帮助你做你所需要的。

基本示例:

#!/usr/bin/env perl

use strict;
use warnings;

use Capture::Tiny 'capture';

my ($stdout, $stderr, $return) = capture {
  system( 'echo Hello' );
};

print "STDOUT: $stdout\n";
print "STDERR: $stderr\n";
print "Return: $return\n";

重读后你可能真的希望capture_merged 将 STDOUT 和 STDERR 加入一个变量,但我给出的示例很好且通用,所以我将不再使用它。

【讨论】:

    【解决方案2】:

    其实正确的写法是:

    #!/usr/bin/perl
    $cmd = 'lsss';  
    my $out=qx($cmd 2>&1);
    my $r_c=$?;
    print "output was $out\n";
    print "return code = ", $r_c, "\n";
    

    如果没有错误,您将获得“0”,如果错误,您将获得“-1”。

    【讨论】:

      【解决方案3】:

      STDERR 旨在用于可能需要从STDOUT 输出流中分离出来的错误或消息。因此,我不希望从像 less 这样的命令的输出中得到任何 STDERR。

      如果你想要两个(或一个)流和返回码,你可以这样做:

      my $out=qx($cmd 2>&1);
      my $r_c=$?
      print "output was $out\n";
      print "return code = ", $r_c == -1 ? $r_c : $r_c>>8, "\n";
      

      如果该命令不可执行(可能是因为您打算使用less,但改为使用lsss),则返回码将为-1。否则,正确的退出值是高 8 位。见system。

      【讨论】:

        【解决方案4】:

        这个问题的一个常见答案是使用包含 shell 类型重定向的命令行。但是,假设您想避免这种情况,并将 open() 与命令和参数列表一起使用,因此您不必担心 shell 如何解释输入(可能部分由用户提供的值组成)。然后不借助 IPC::Open3 等包,以下内容将同时读取 stdout 和 stderr:

        my ($child_pid, $child_rc);
        
        unless ($child_pid = open(OUTPUT, '-|')) {
          open(STDERR, ">&STDOUT");
          exec('program', 'with', 'arguments');
          die "ERROR: Could not execute program: $!";
        }
        waitpid($child_pid, 0);
        $child_rc = $? >> 8;
        
        while (<OUTPUT>) {
          # Do something with it
        }
        close(OUTPUT);
        

        【讨论】:

        • 这是该线程中的最佳答案。使用更多代码,它将阻止使用 shell 重定向,通常是 bash。如果你详细评论它,这个例子会更好。但在 perldoc open function 中有详细描述。
        • 有一个重要的问题,为什么要先等待子进程并检查 RC,然后再读取它的输出?我觉得应该换掉。我认为这只是它正常工作的一个原因,它是操作系统进行的管道缓冲。我认为如果外部“程序”会因为流重定向而在 stdout 或 stderr 上产生大流,它会挂起。
        猜你喜欢
        • 1970-01-01
        • 2023-04-05
        • 1970-01-01
        • 1970-01-01
        • 2021-05-29
        • 2020-06-23
        • 2023-03-23
        • 1970-01-01
        相关资源
        最近更新 更多