如何以异步方式在Perl中运行系统命令?
我目前有一个Perl脚本,它在系统上运行一个外部命令,收集输出,并根据返回的内容执行一些操作。现在,这里是我如何运行这个(其中$ cmd是用命令设置一个字符串):如何以异步方式在Perl中运行系统命令?
@output = `$cmd`;
我想改变这种做法,如果命令挂起,不经过这么多的返回值那么我会杀死这个命令。我将如何去异步运行它?
如果你真的只需要在给定的系统调用上放一个超时,这是一个比异步编程简单得多的问题。
所有你需要的是一个eval()块内部的alarm()。
下面是一个示例代码块,它将这些代码放入可以放入代码的子例程中。该示例调用睡眠等都不是令人兴奋的输出,但不告诉你,你有兴趣的超时功能,运行它的 输出为:
/斌/睡眠2失败:超时在 ./time退房手续线15
$ cat time-out
#!/usr/bin/perl
use warnings;
use strict;
my $timeout = 1;
my @cmd = qw(/bin/sleep 2);
my $response = timeout_command($timeout, @cmd);
print "$response\n" if (defined $response);
sub timeout_command {
my $timeout = (shift);
my @command = @_;
undef [email protected];
my $return = eval {
local($SIG{ALRM}) = sub {die "timeout";};
alarm($timeout);
my $response;
open(CMD, '-|', @command) || die "couldn't run @command: $!\n";
while(<CMD>) {
$response .= $_;
}
close(CMD) || die "Couldn't close execution of @command: $!\n";
$response;
};
alarm(0);
if ([email protected]) {
warn "@cmd failure: [email protected]\n";
}
return $return;
}
有办法做到这一点很多:
- 您可以用叉子(参阅perldoc -f叉)
- 或使用线程(线程的perldoc)做到这一点。这两种方法都会使返回的信息难以回到主程序。
- 在支持它的系统上,您可以设置一个警报(perldoc -f警报),然后在信号处理程序中进行清理。
- 您可以使用像POE或Coro这样的事件循环。
- 除了反引号之外,您可以使用open()或open2或open3(参见IPC :: Open2,IPC :: Open3)来启动程序,同时通过文件句柄获取STDOUT/STDERR。在其上运行非阻塞式读取操作。 (perldoc -f选择和可能谷歌“perl nonblocking读”)
- 作为一个更强大的变种的openX()的,检查出IPC :: Run/IPC :: Cmd。
- 大概是我在半夜想不到的吨。
在Win32系统当心破'select'只用于插座和与控制台窗口可能奇怪反应工程,wperl(运行在一个非控制台窗口的方式perl的,但对STDIO和子进程有奇怪的影响)。在好的一面,你可以做一个'system(-1,'foo')'。此外,运行64个子项后,某些启动进程的方式失败。 IME,'Win32 :: Process :: Create()'是在bgrnd中运行程序最安全的方法。 – daotoad 2009-11-18 01:10:24
@daotoad,感谢您的评论。我缺乏win32线索表明我唯一知道的是fork()是用线程模拟的,而且你不能使用警报。我猜如果涉及win32,IPC :: Cmd将是一个不错的选择。 – tsee 2009-11-18 08:46:00
如果你的外部程序不带任何输入,寻找在perlipc
手册页下面的话:
这里是一个安全的反引号或管开放阅读:
使用示例代码并警告它(这也在perlipc
中解释)。
谢谢,这是我所寻找的更多。 – Joel 2009-12-03 16:10:59
我认为你需要在死信息中有一个\ n。 (http://perldoc.perl.org/functions/alarm.html) – ddoxey 2013-04-04 05:04:16