首页 文章

从perl中的external * nix命令获取STDOUT,STDERR和响应代码

提问于
浏览
4

我想从我的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|");

当命令成功运行时,我可以捕获stdout .

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

4 回答

  • 4

    实际上,写这个的正确方法是:

    #!/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' .

  • 5

    这正是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加入到一个变量中,但我给出的例子很好而且很通用,所以我会留下它 .

  • 9

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

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

    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 .

  • 1

    这个问题经常给出的答案是使用包含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);
    

相关问题