什么是首选的跨平台IPC Perl模块?

the*_*ory 16 perl ipc pipe filehandle

我想创建一个简单的IO对象,它表示打开到另一个程序的管道,我可以在我的应用程序运行时定期写入另一个程序的STDIN.我希望它能够防弹(因为它可以捕获所有错误)和跨平台.我能找到的最佳选择是:

open

sub io_read {
    local $SIG{__WARN__} = sub { }; # Silence warning.
    open my $pipe, '|-', @_ or die "Cannot exec $_[0]: $!\n";
    return $pipe;
}
Run Code Online (Sandbox Code Playgroud)

好处:

  • 跨平台
  • 简单

缺点

  • 没有$SIG{PIPE}从管道程序捕获错误
  • 是否有其他错误?

IO ::管

sub io_read {
    IO::Pipe->reader(@_);
}
Run Code Online (Sandbox Code Playgroud)

好处:

  • 简单
  • 返回OO接口的IO :: Handle对象
  • 由Perl核心支持.

缺点

  • 仍然没有$SIG{PIPE}从管道程序中捕获错误
  • Win32不支持(或者,至少,它的测试被跳过)

IPC ::运行

在IPC :: Run中没有用于写入文件句柄的接口,只是附加到标量.这似乎......很奇怪.

IPC :: RUN3

这里也没有文件句柄接口.我可以使用代码引用,它将被重复调用以假脱机到子代,但是看看源代码,它似乎实际写入临时文件,然后打开它并将内容假脱机到管道命令STDIN.世界卫生大会?

IPC :: Cmd的

仍然没有文件句柄接口.


我在这里错过了什么?似乎这应该是一个已经解决的问题,而且我有点惊讶它不是.IO :: Pipe最接近我想要的,但缺乏$SIG{PIPE}错误处理和缺乏对Windows的支持是令人痛苦的.JDWIM的管道模块在哪里?

the*_*ory 6

感谢@ikegami的指导,我发现在Perl中以交互方式读取和写入另一个进程的最佳选择是IPC :: Run.但是,它要求您正在读取和写入的程序在写入其STDOUT时具有已知输出,例如提示.这是一个执行的示例,bash运行它ls -l,然后打印输出:

use v5.14;
use IPC::Run qw(start timeout new_appender new_chunker);

my @command = qw(bash);

# Connect to the other program.
my ($in, @out);
my $ipc = start \@command,
    '<' => new_appender("echo __END__\n"), \$in,
    '>' => new_chunker, sub { push @out, @_ },
    timeout(10) or die "Error: $?\n";

# Send it a command and wait until it has received it.
$in .= "ls -l\n";
$ipc->pump while length $in;

# Wait until our end-of-output string appears.
$ipc->pump until @out && @out[-1] =~ /__END__\n/m;

pop @out;
say @out;
Run Code Online (Sandbox Code Playgroud)

因为它是作为IPC运行的(我假设),bash所以在写入STDOUT时不会发出提示.所以我使用new_appender()函数让它发出一些我可以匹配的东西来找到输出的结尾(通过调用echo __END__).我在调用之后还使用了一个匿名子例程new_chunker来将输出收集到数组中,而不是标量('>'如果你想要的话,只需将标量的引用传递给它).

所以这很有效,但在我看来,它有很多原因:

  • 通常没有一种有用的方法可以知道IPC控制的程序是否已经打印到STDOUT.相反,您必须在其输出上使用正则表达式来搜索通常意味着已完成的字符串.
  • 如果它没有发出一个,你必须欺骗它发射一个(就像我在这里做的那样 - 上帝禁止,如果我应该有一个名字的文件__END__).如果我在控制数据库客户端,我可能需要发送类似的东西SELECT 'IM OUTTA HERE';.不同的应用需要不同的new_appender黑客攻击.
  • 对魔法$in$out标量的写作感觉很奇怪,并且在远处行动.我不喜欢它.
  • 如果它们是文件句柄,就不能对标量进行面向行的处理.因此效率较低.
  • new_chunker如果仍然有点奇怪,使用获取面向行的输出的能力是很好的.然而,假设它被IPC :: Run有效缓冲,那么重新获得了从程序读取输出的效率.

我现在意识到,尽管IPC :: Run的界面可能会更好一些,但总体而言,IPC模型的弱点使得处理它变得棘手.没有通用的IPC接口,因为人们必须对运行的特定程序的具体细节了解太多才能使其工作.这是正常的,也许,如果你知道它究竟是如何给输入的反应,而当它完成发射输出能够可靠地识别,并且不需要得多担心跨平台的兼容性.但这远远不足以满足我对CPAN模块中各种数据库命令行客户端进行交互的通用方法的需求,这些客户端可以分发到整个操作系统主机.

最后,由于博客文章评论中的打包建议,我决定放弃使用IPC来控制这些客户端,而是使用DBI.它提供了出色的API,强大,稳定,成熟,并且没有IPC的缺点.

我对那些追随我的人的建议如下:

  • 如果您只需要执行另一个程序并等待它完成,或者在运行完毕后收集它的输出,请使用IPC :: System :: Simple.否则,如果您需要做的是以交互方式与其他内容交互,请尽可能使用API​​.如果不可能的话,那就使用像IPC :: Run这样的东西,尽量充分利用它 - 并准备好放弃相当多的时间来"恰到好处".