2015-12-24 5 views
5

Wenn ich eine lang andauernde system Befehl wie apt-cache search <some query>, haben, ist es eine Möglichkeit, einen SIGINT gesendet über ^C auf der Kommandozeile zu dem übergeordneten Perl-Prozess in einer solchen Art und Weise zu übermitteln dass alle untergeordneten Prozesse geerntet werden.Perl SIGINT uns auf Eltern-Prozess von `system` Befehl

Dieses Beispiel hat nicht das gewünschte Verhalten. Das Signal wird an den Kindprozess gesendet.

#!/usr/bin/env perl 
use strict; 
use warnings FATAL => 'all'; 
use autodie; 

# long running command on ubuntu, produces a ton of output. 
# replace with your favorite long running command 
system("apt-cache search hi"); 

print("Perl did not catch SIGINT even with autodie\n"); 

Ich habe versucht, um nach Möglichkeiten zu suchen, die pid des Kindes erfassen, die von system("apt-cache search hi &") erstellt werden würde, aber keine finden konnte, so habe ich versucht, fork ing und exec den Prozess ing und einen Signal-Handler zu schreiben. Dies funktioniert nicht, da apt-cache selbst einige Prozesse über den Systemaufruf clone startet. Handwalzen eine gewisse Logik Teil des Prozesses Baum zu gehen und die

#!/usr/bin/env perl 
use strict; 
use warnings FATAL => 'all'; 
use autodie; 

my $cpid; 

$SIG{INT} = sub { 
    kill 'KILL', $cpid; 
    exit; 
}; 

# long running command on ubuntu, produces a ton of output. 
# replace with your favorite long running command 
$cpid = fork; 
if ($cpid == 0) { 
    exec 'apt-cache', 'search', 'hi'; 
} 

print "Perl did not catch SIGINT even with autodie\n"; 

ich im Wesentlichen erraten aufzuräumen, was ich will, ist entweder eine Art und Weise, ob ein Kind Prozess durch system verlassen wegen eines Signals wie SIGINT so startete der Bestimmung Ich kann das Perl-Skript nach sich selbst aufräumen lassen oder die Kindprozesse durchlaufen und sie so ernten, dass seltsame Randfälle der Prozessverwaltung sauber und portabel gehandhabt werden.

+0

'IPC :: Run 'kann sein, was Sie brauchen, anstatt System. Oder setzen Sie einfach "SIGCHLD" auf "IGNORE", damit sie beim Beenden automatisch erkannt werden. – Sobrique

+0

Hier können Sie feststellen, ob der Befehl vom Benutzer abgebrochen wurde: siehe [Name der Signalnummer 2] (http://stackoverflow.com/questions/29862178/name-of-signal-number-2) –

+0

Siehe auch [Wie starte ich einen Prozess in seiner eigenen Prozessgruppe?] (Http://stackoverflow.com/questions/5809034/in-linux-how-to-start-a-process-in-its-its-own-process-group- und-mehr) –

Antwort

6

Machen Sie das Kind zum Kopf einer Prozessgruppe und senden Sie das Signal an die gesamte Prozessgruppe.

#!/usr/bin/perl 

use strict; 
use warnings; 
use autodie; 

use POSIX qw(setpgid); 

my $child_pid; 

$SIG{INT} = sub { 
    kill INT => -$child_pid if $child_pid; 
    exit(0x80 | 2); # 2 = SIGINT 
}; 

my $child_pid = fork(); 
if (!$child_pid) { 
    setpgid($$); 
    exec 'apt-cache', 'search', 'hi'; 
} 

WAIT: { 
    no autodie; 
    waitpid($child_pid, 0); 
    redo WAIT if $? == -1 and $!{EINTR}; 
    die $! if $? == -1; 
} 

exit(($? >> 8) | (0x80 | ($? & 0x7F))); 
+0

'kill INT => - $ child_pid wenn $ child_pid;' ist das Windows-spezifisch? –

+1

Nein, ziemlich genau das Gegenteil. Windows hat keine POSIX-Signale oder Prozessgruppen (obwohl 'kill' verwendet werden kann, um eines der wenigen Signale, die Windows hat, Ctrl-C und Ctrl-Break an eine Konsolen-App zu senden). – ikegami

+0

Also, was macht das Negieren der CPID? –

Verwandte Themen