簡體   English   中英

Perl - 如果需要很長時間,就會在按鍵上打破系統/反引號命令

[英]Perl - Breaking out of a system/backticks command on keypress if it takes a long time

我有一個問題,我希望有人可以幫助...

我有一個foreach循環,在每次迭代時執行反引號命令,例如在目錄中為字符串greping一個文件夾(如下所示,為了解釋我的問題,大大簡化了)。

my @folderList = ("/home/bigfolder", "/home/hugefolder", "/home/massivefolder");
my @wordList = ("hello", "goodbye", "dog", "cat");

foreach my $folder (@folderList) {
     foreach my $word (@wordList) {
          print "Searching for this $word in this $folder\n";
          my @output = `grep -R $word $folder`;    #this could take hours so the user needs the option to skip/cancel this iteration and go the next one 
          print "@output\n";
     }
}

我遇到的問題:

如果反向運行反引號grep命令的文件夾特別大或者要檢查的單詞數組特別大,那么反引號命令可能需要數小時才能完成(這很好)。

但我想要做的是打破內循環(即當一個單詞在一個文件夾中被greped)並進入下一次迭代,如果用戶按下一個鍵需要很長時間例如,鍵盤或輸入單詞“next”或“exit”。

我知道如果我不使用反引號,我可以使用類似下面的內容輕松突破正常循環(但是當涉及反引號/系統調用時,這顯然不起作用):

use strict;
use warnings;

use Term::ReadKey;

my $n = 0;

while () {
    print '.';
    last if ReadKey(-1);
    $n++;
}

print $n;

可能有一個簡單的解決方案,我忽略了,但我以前從未有過這樣的需要,所以非常感謝您的幫助,謝謝

解決方案是在后台進程中運行長時間運行的程序(並記住新進程的進程ID),並在前台進程中保持用戶交互。 當前景被指示中斷時,終止后台進程。

我提到的所有部分都在之前關於Stack Overflow的帖子中得到了很好的解釋。

您正在嘗試同時運行外部命令並處理鍵盤事件,因此您需要使用一些異步框架。 異步框架基於forks,線程或事件循環,在這種情況下,事件循環不合適。

以下是如何使用fork的概述:

use POSIX ':sys_wait_h';  # defines WNOHANG

foreach my $folder (@folderList) {
     foreach my $word (@wordList) {
          print "Searching for this $word in this $folder\n";

          my $pid = fork();
          if ($pid == 0) {  # child process
              # we are just printing output from the child process; if you want
              # to move data from the child process back to the parent, well,
              # that's a whole other can of worms
              print `grep -R $word $folder`;
              exit;
          } else {          # parent process
              while (waitpid($pid, &WNOHANG) != $pid) {
                  if (Term::ReadKey(-1)) {
                      kill 'TERM', $pid;    # or maybe kill 'KILL', ...
                      last;
                  }
              }
          }
     }
}

我理解人們對后台進程,線程和分叉等所說的內容, 但最適合我安排的選項 (並且可能更容易實現),盡管我承認可能不是最有效,最佳實踐或首選這樣做的方式,涉及使用eval和捕獲用戶control-c按鍵。

很簡單的例子:

NEXT:foreach $folder (@folders) {     #label on the foreach

         eval {
               $SIG{INT} = sub { break() };   #catches control-c keypress and calls the break subroutine
               $var1 = `grep -r "hello" $folder`;
         };

         sub break {
              print "Breaking out of the backticks command and going to next folder \n";
              next NEXT;  
         }

     } #ending bracket of foreach loop

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM