Perl:在完成执行之前移动到循环中的下一个项目

时间:2015-02-03 08:07:59

标签: perl loops foreach

我有一个类似的perl脚本:

foreach my $addr ('http://site1.com', ...., 'http://site2.com') {
    my $script = `curl -m 15 $addr`;
    *do stuff with $script*
} 

-m设置超时15秒。有没有办法让用户按下一个键,它会停止当前执行并移动到foreach中的下一个项目?我知道last;可以移动到下一个项目,但我不确定如何将此链接到正在推送的密钥以及如何在curl脚本运行时执行此操作

编辑:因此,基于答案,在curl运行时似乎很难做到这一点。是否可以在curl运行时按下一个键,并且只要 curl脚本返回(或在15秒后超时)就跳到循环中的下一个项目?

2 个答案:

答案 0 :(得分:4)

你遇到的问题是,当你运行curl perl over over control并等待完成时。它会阻塞直到它完成。

所以这并不像看起来那么容易。

正如另一张海报所暗示的那样 - 您可以使用各种并行处理选项。我建议最简单的方法是不要使用'any'键,并且需要一个ctrl-c。

那你就做了:

foreach my $addr ('http://site1.com', ...., 'http://site2.com') {
     my $pid = open ( my $curl_fh, "-|", "curl -m 15 $addr" );
     $SIG{'INT'} = sub { print "Aborting fetch of $addr"; kill $pid };
     while ( <$curl_fh> ) {
         print;
     }
     #might want to set it to something else. 
     #undef means 'ctrl-c' will abort the whole program. 
     #IGNORE means exactly what it says on the tin.
     #important to change it though, as it has a specific pid it'll kill, 
     #and that might cause problems. 
     $SIG{'INT'} = undef;
} 

这样做是配置SIGINT(例如ctrl-c)所以它不会杀死你的程序,但会杀死子进程。

如果您想查看其他选项,我会提供:

  • 多线程,产生一个线程来“执行”在后台获取的卷曲,并使用Thread::Queue来回传递结果。 (Thread::Queue支持非阻塞检查)。

  • 分叉 - 分叉子进程进行卷曲,如果按下某个键,则使用'main'进程发送信号。

  • IO::Select这样您就不会对您的流程进行阻止读取。

答案 1 :(得分:2)

基本上你有两个选择:

<强> 1。使用线程

创建一个新线程,在那里调用所需的系统函数。等待输出。在另一个线程中,检查用户输入。在输入时,您可以终止子进程。子进程完成后,您可以忽略用户输入。

这样的解决方案似乎相当复杂,需要大量同步,可能使用信号。有风险的。

<强> 2。使用非阻塞IO

请阅读this帖子。它解释了如何从文件或管道进行非阻塞IO读取。您希望从管道(使用open创建)进行非阻塞读取,然后从STDIN进行无阻塞读取循环。

似乎是一种可行的方式,但是,唉,相当复杂。