如何在Perl中异步运行系统命令?

时间:2009-11-17 22:34:34

标签: perl

我目前有一个Perl脚本,它在系统上运行外部命令,收集输出,并根据返回的内容执行一些操作。现在,这是我如何运行它(其中$ cmd是一个带有命令设置的字符串):

@output = `$cmd`;

我想改变它,所以如果命令挂起并且在这么多时间之后没有返回值,那么我会终止命令。我将如何异步运行?

3 个答案:

答案 0 :(得分:12)

有很多方法可以做到这一点:

  • 您可以使用fork(perldoc -f fork)
  • 执行此操作
  • 或使用线程(perldoc线程)。这两个都使返回的信息难以传回主程序。
  • 在支持它的系统上,您可以设置警报(perldoc -f警报),然后在信号处理程序中清理。
  • 您可以使用POE或Coro等事件循环。
  • 您可以使用open()或open2或open3(参见IPC :: Open2,IPC :: Open3)来启动程序,同时通过文件句柄获取STDOUT / STDERR,而不是反引号。对其运行非阻塞读取操作。 (perldoc -f select,可能是google“perl nonblocking read”)
  • 作为openX()的更强大的变体,请查看IPC :: Run / IPC :: Cmd。
  • 可能是我半夜想不到的。

答案 1 :(得分:8)

如果你真的只需要在给定的系统调用上设置超时,这比异步编程要简单得多。

您需要的是eval()块内的alarm()。

下面是一个示例代码块,它将这些代码块放入您可以放入代码的子例程中。该示例调用sleep,因此输出并不令人兴奋,但会显示您感兴趣的超时功能。 运行它的输出是:

  

/ bin / sleep 2失败:超时时间   ./time-out第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 $@;
        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 ($@) {
                warn "@cmd failure: $@\n";
        }
        return $return;
}

答案 2 :(得分:1)

如果您的外部程序未接受任何输入,请在perlipc联机帮助页中查找以下字词:

  

这是一个安全的反推或管道打开阅读:

使用示例代码并使用警报进行保护(perlipc中也对此进行了解释)。