如何从Perl脚本中捕获系统命令的stdin和stdout?

时间:2020-03-05 18:57:26  来源:igfitidea点击:

在Perl脚本的中间,有一个我要执行的系统命令。我有一个字符串,其中包含需要输入到stdin中的数据(该命令仅接受来自stdin的输入),并且我需要捕获写入stdout的输出。我研究了Perl中执行系统命令的各种方法," open"函数似乎是我所需要的,除了看起来我只能捕获stdin或者stdout,不能同时捕获两者。

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

解决方案

回答

IPC :: Open3可能会做我们想要的。它可以捕获STDERR和STDOUT。

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

回答

我想我们想看看IPC :: Open2

回答

有一个特殊的perl命令

open2()

可以在以下位置找到更多信息:http://sunsite.ualberta.ca/Documentation/Misc/perl-5.6.1/lib/IPC/Open2.html

回答

在脚本顶部的某处,添加以下行

use IPC::Open2;

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

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

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

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

回答

如果我只希望输出一行,或者想将结果分割到换行符以外的其他地方,我总是这样做

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();  
    }  
}

回答

perlipc文档涵盖了许多方法,包括IPC :: Open2和IPC :: Open3.

回答

IPC :: Open2 / 3很好,但是我发现通常我真正需要的只是IPC :: Run3,它能够以最小的复杂性很好地处理简单的情况:

use IPC::Run3;    # Exports run3() by default

run3( \@cmd, $in, $out, $err );

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

回答

如果我们不希望包含额外的程序包,则可以执行以下操作

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

这与建议相反,但也应该起作用。

回答

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

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

请注意,如果将列表传递给命令,它将如何在不通过外壳的情况下调用命令。它还可以很好地处理常见实用程序的错误。 (如果失败,则使用STDERR中的文本作为错误消息,使其"死亡";如果成功,则仅丢弃STDERR。)

当然,它不适合处理大量数据,因为它无法进行任何流处理。同样,错误处理的粒度可能不足以满足需求。但这使许多简单的情况确实非常简单。