【问题标题】:How can I capture the stdin and stdout of system command from a Perl script?如何从 Perl 脚本中捕获系统命令的标准输入和标准输出?
【发布时间】:2010-09-09 20:04:32
【问题描述】:

在 Perl 脚本的中间,有一个我要执行的系统命令。我有一个字符串,其中包含需要输入标准输入的数据(该命令只接受来自标准输入的输入),我需要捕获写入标准输出的输出。我查看了在 Perl 中执行系统命令的各种方法,open 函数似乎是我所需要的,除了它看起来我只能捕获标准输入或标准输出,而不是两者。

目前,似乎我最好的解决方案是使用open,将标准输出重定向到一个临时文件,并在命令完成后从文件中读取。有没有更好的解决方案?

【问题讨论】:

    标签: perl ipc


    【解决方案1】:

    IPC::Open2/3 很好,但我发现通常我真正需要的只是IPC::Run3,它可以很好地处理简单的情况,而且复杂度最低:

    use IPC::Run3;    # Exports run3() by default
    
    run3( \@cmd, \$in, \$out, \$err );
    

    该文档将 IPC::Run3 与其他替代方案进行了比较。即使您不决定使用它也值得一读。

    【讨论】:

      【解决方案2】:

      perlipc documentation 涵盖了您可以执行此操作的多种方式,包括 IPC::Open2 和 IPC::Open3。

      【讨论】:

        【解决方案3】:

        在脚本顶部的某处,包含该行

        use IPC::Open2;
        

        这将包括必要的模块,通常默认安装在大多数 Perl 发行版中。 (如果你没有它,你可以使用 CPAN 安装它。)然后,而不是打开,调用:

        $pid = open2($cmd_out, $cmd_in, 'some cmd and args');
        

        您可以通过将数据发送到 $cmd_in 来将数据发送到您的命令,然后通过读取 $cmd_out 来读取命令的输出。

        如果您还希望能够读取命令的 stderr 流,则可以改用 IPC::Open3 模块。

        【讨论】:

        • 对于阅读本文的任何人,您应该确保不要像本示例那样使用裸字文件句柄。请参阅此文档:perlfoundation.org/perl5/…
        【解决方案4】:

        IPC::Open3 可能会做你想做的事。它可以捕获STDERR和STDOUT。

        http://metacpan.org/pod/IPC::Open3

        【讨论】:

          【解决方案5】:

          我最近发现的一个非常简单的方法是IPC::Filter 模块。它让您可以非常直观地完成工作:

          $output = filter $input, 'somecmd', '--with', 'various=args', '--etc';
          

          请注意,如果您将列表传递给它,它会如何在不通过 shell 的情况下调用您的命令。它还可以合理地处理常见实用程序的错误。 (失败时,它dies,使用来自 STDERR 的文本作为其错误消息;成功时,STDERR 将被丢弃。)

          当然,它不适合处理大量数据,因为它无法进行任何流式处理;此外,错误处理可能不足以满足您的需求。但它使许多简单的案例变得非常非常简单。

          【讨论】:

            【解决方案6】:

            我想你想看看IPC::Open2

            【讨论】:

              【解决方案7】:

              它有一个特殊的 perl 命令

              open2()
              

              更多信息请访问:http://sunsite.ualberta.ca/Documentation/Misc/perl-5.6.1/lib/IPC/Open2.html

              【讨论】:

              • 哥们,为什么要发已经发过的东西?
              【解决方案8】:

              如果你不想包含额外的包,你可以这样做

              open(TMP,">tmpfile");
              print TMP  $tmpdata ;
              open(RES,"$yourcommand|");
              $res = "" ;
              while(<RES>){
              $res .= $_ ;
              }
              

              这与您的建议相反,但也应该有效。

              【讨论】:

                【解决方案9】:

                如果我只期望单行输出或希望将结果拆分为换行符以外的其他内容,我总是这样做:

                my $result = qx( command args 2>&1 );  
                my $rc=$?;  
                # $rc >> 8 is the exit code of the called program.
                
                if ($rc != 0 ) {  
                    error();  
                }  
                

                如果要处理多行响应,将结果作为数组获取:

                my @lines = qx( command args 2>&1 );  
                
                foreach ( my $line ) (@lines) {  
                    if ( $line =~ /some pattern/ ) {  
                        do_something();  
                    }  
                }  
                

                【讨论】:

                • 我看不到您的示例在哪里处理 STDIN。
                猜你喜欢
                • 2011-07-05
                • 1970-01-01
                • 2021-06-24
                • 2011-12-13
                • 2012-03-16
                • 1970-01-01
                • 2014-02-02
                • 1970-01-01
                • 2021-04-29
                相关资源
                最近更新 更多