如何从Perl脚本中捕获系统命令的stdin和stdout?
在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。)
当然,它不适合处理大量数据,因为它无法进行任何流处理。同样,错误处理的粒度可能不足以满足需求。但这使许多简单的情况确实非常简单。