[英]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.