私は誰かが助けてくれることを望んでいる問題があります...
バックティックを実行するforeachループがあります文字列のディレクトリ内のフォルダをgrepするなど、各反復でのコマンド(以下に示すように、私の質問を説明するために大幅に簡略化されています)。
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 $foldern";
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 "@outputn";
}
}
私が抱えている問題:
フォルダーがbackticksgrepコマンドである場合実行が特に大きいか、チェックする単語の配列が特に大きい場合、backticksコマンドが完了するまでに数時間かかることがあります(これは問題ありません)。
しかし、私がしたいのは、脱出することですユーザーがキーボードのキーを押すか、「次へ」または「終了」という単語を入力するのに時間がかかる場合は、内側のループの例えば。
バックティックを使用していなかった場合は、次のようなものを使用して、通常のループから簡単に抜け出すことができます(ただし、バックティック/システムコールが含まれている場合、このロジックは明らかに機能しません)。
use strict;
use warnings;
use Term::ReadKey;
my $n = 0;
while () {
print ".";
last if ReadKey(-1);
$n++;
}
print $n;
私が見落としている簡単な解決策があるかもしれませんが、私はこれまでこれを行う必要がなかったので、あなたの助けに感謝します
回答:
回答№1は2解決策は、長時間実行されるプログラムを実行することですバックグラウンドプロセスで(そして新しいプロセスのプロセスIDを覚えて)、フォアグラウンドプロセスでのユーザーインタラクションを維持します。前景が壊れるように通知されたら、バックグラウンドプロセスを強制終了します。
私が言及したすべての部分は、StackOverflowに関する以前の投稿で十分に説明されています。
回答№2の場合は1
外部を同時に実行しようとしていますコマンドを実行してキーボードイベントを処理するため、非同期フレームワークを使用する必要があります。非同期フレームワークは、フォーク、スレッド、またはイベントループのいずれかに基づいており、この場合、イベントループは適切ではありません。
フォークの使用方法の概要は次のとおりです。
use POSIX ":sys_wait_h"; # defines WNOHANG
foreach my $folder (@folderList) {
foreach my $word (@wordList) {
print "Searching for this $word in this $foldern";
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;
}
}
}
}
}
回答№3の場合は0
バックグラウンドプロセス、スレッド、フォークなどに関して人々が言ったことを理解しています。 しかし、私の配置に最も適したオプション (そしておそらく実装するのが簡単です)、私はそれを行うための最も効率的でベストプラクティスまたは好ましい方法ではないかもしれませんが、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