首选的跨平台IPC Perl模块是什么? [英] What is the preferred cross-platform IPC Perl module?

查看:76
本文介绍了首选的跨平台IPC Perl模块是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to create a simple IO object that represents a pipe opened to another program to that I can periodically write to another program's STDIN as my app runs. I want it to be bullet-proof (in that it catches all errors) and cross-platform. The best options I can find are:

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

优势:

  • 跨平台
  • 简单

缺点

  • $SIG{PIPE}不能从管道程序中捕获错误
  • 还发现其他错误吗?
  • No $SIG{PIPE} to catch errors from the piped program
  • Are other errors caught?
sub io_read {
    IO::Pipe->reader(@_);
}

优势:

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

缺点

  • Still No $SIG{PIPE} to catch errors from the piped program
  • Not supported on Win32 (or, at least, its tests are skipped)

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

There is no interface for writing to a file handle in IPC::Run, only appending to a scalar. This seems…weird.

这里也没有文件句柄接口.我可以使用一个代码引用,该引用将被反复调用以假脱机到该子级,但查看源代码,它似乎实际上写入了一个临时文件,然后打开它并假脱机内容添加到管道命令的STDIN中.嗯?

No file handle interface here, either. I could use a code reference, which would be called repeatedly to spool to the child, but looking at the source code, it appears that it actually writes to a temporary file, and then opens it and spools its contents to the pipe'd command's STDIN. Wha?

仍然没有文件句柄界面.

Still no file handle interface.

我在这里想念什么?似乎这应该是一个已解决的问题,但我有些异,事实并非如此. IO :: Pipe最接近我想要的内容,但是缺少$SIG{PIPE}错误处理和对Windows的支持令人苦恼. JDWIM的管道模块在哪里?

What am I missing here? It seems as if this should be a solved problem, and I'm kind of stunned that it's not. IO::Pipe comes closest to what I want, but the lack of $SIG{PIPE} error handling and the lack of support for Windows is distressing. Where is the piping module that will JDWIM?

推荐答案

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

Thanks to guidance from @ikegami, I have found that the best choice for interactively reading from and writing to another process in Perl is IPC::Run. However, it requires that the program you are reading from and writing to have a known output when it is done writing to its STDOUT, such as a prompt. Here's an example that executes bash, has it run ls -l, and then prints that output:

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;

由于它正在作为IPC运行(我假设),因此bash在完成向其STDOUT的写入操作时不会发出提示.因此,我使用new_appender()函数使它发出可以匹配的内容,以找到输出的结尾(通过调用echo __END__).在调用new_chunker之后,我还使用了一个匿名子例程将输出收集到一个数组中,而不是一个标量(如果需要的话,只需将对标量的引用传递给'>'即可).

Because it is running as an IPC (I assume), bash does not emit a prompt when it is done writing to its STDOUT. So I use the new_appender() function to have it emit something I can match to find the end of the output (by calling echo __END__). I've also used an anonymous subroutine after a call to new_chunker to collect the output into an array, rather than a scalar (just pass a reference to a scalar to '>' if you want that).

这是可行的,但我认为它很糟糕,原因很多:

So this works, but it sucks for a whole host of reasons, in my opinion:

  • 没有一般有用的方法来知道IPC控制的程序已完成向其STDOUT的打印.相反,您必须在其输出上使用正则表达式来搜索通常表示已完成的字符串.
  • 如果它不发出一个,则必须欺骗它发出一个(如我在这里所做的,但是如果我应该有一个名为__END__的文件,上帝会禁止的).如果我正在控制数据库客户端,则可能必须发送类似SELECT 'IM OUTTA HERE';的内容.不同的应用程序将需要不同的new_appender黑客.
  • 写魔术标量$in$out感觉很奇怪,而且动作距离很远.我不喜欢它.
  • 如果它们是文件句柄,则不能像在标量上那样进行面向行的处理.因此,它们的效率较低.
  • 使用new_chunker获得面向行的输出的功能非常不错,即使仍然有些怪异.但是,假定它已被IPC :: Run有效缓冲,则从读取程序的输出中重新获得了一定的效率.
  • There is no generally useful way to know that an IPC-controlled program is done printing to its STDOUT. Instead, you have to use a regular expression on its output to search for a string that usually means it's done.
  • If it doesn't emit one, you have to trick it into emitting one (as I have done here—god forbid if I should have a file named __END__, though). If I was controlling a database client, I might have to send something like SELECT 'IM OUTTA HERE';. Different applications would require different new_appender hacks.
  • The writing to the magic $in and $out scalars feels weird and action-at-a-distance-y. I dislike it.
  • One cannot do line-oriented processing on the scalars as one could if they were file handles. They are therefore less efficient.
  • The ability to use new_chunker to get line-oriented output is nice, if still a bit weird. That regains a bit of the efficiency on reading output from a program, though, assuming it is buffered efficiently by IPC::Run.

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

I now realize that, although the interface for IPC::Run could potentially be a bit nicer, overall the weaknesses of the IPC model in particular makes it tricky to deal with at all. There is no generally-useful IPC interface, because one has to know too much about the specifics of the particular program being run to get it to work. This is okay, maybe, if you know exactly how it will react to inputs, and can reliably recognize when it is done emitting output, and don't need to worry much about cross-platform compatibility. But that was far from sufficient for my need for a generally useful way to interact with various database command-line clients in a CPAN module that could be distributed to a whole host of operating systems.

最后,感谢在博客文章中的注释中提供了打包建议,我决定放弃使用IPC控制那些客户端,而使用 DBI , 反而.它提供了出色的API,健壮,稳定且成熟,并且没有IPC的缺点.

In the end, thanks to packaging suggestions in comments on a blog post, I decided to abandon the use of IPC for controlling those clients, and to use the DBI, instead. It provides an excellent API, robust, stable, and mature, and suffers none of the drawbacks of IPC.

我对那些追随我的人的建议是:

My recommendation for those who come after me is this:

  • 如果您只需要执行另一个程序并等待其完成,或者在运行完成后收集其输出,请使用 IPC :: Run 之类的方法,尝试使尽力而为-并准备放弃您的大量时间以使其恰到好处".
  • If you just need to execute another program and wait for it to finish, or collect its output when it is done running, use IPC::System::Simple. Otherwise, if what you need to do is to interactively interface with something else, use an API whenever possible. And if it's not possible, then use something like IPC::Run and try to make the best of it—and be prepared to give up quite a bit of your time to get it "just right."

这篇关于首选的跨平台IPC Perl模块是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆