2015-12-24 6 views
5

Se ho una lunga durata system comando come apt-cache search <some query>, c'è un modo per trasmettere una SIGINT inviata via ^C sulla riga di comando per il processo Perl genitore in tale maniera che tutti i processi figli sono raccolti.Perl avanti SIGINT al processo padre da `comando system`

Questo esempio non ha il comportamento desiderato. Il segnale viene inviato al processo figlio.

#!/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"); 

Ho provato a cercare in giro per le vie di catturare il pid del figlio che sarebbe stato creato da system("apt-cache search hi &"), ma non riusciva a trovare alcuna, così ho provato fork ING e exec ing il processo e la scrittura di un gestore di segnale. Questo non funziona perché lo stesso apt-cache avvia alcuni processi tramite la chiamata di sistema clone. Hand-rolling una logica di camminare parte dell'albero processo e ripulire il

#!/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"; 

Credo che in sostanza quello che voglio o è un modo per determinare se un processo figlio lanciato da system uscito a causa di un segnale come SIGINT così Posso fare in modo che lo script Perl ripulisca se stesso o un modo di camminare i processi figli e raccoglierli in modo tale che gli strani casi limite della gestione dei processi siano gestiti in modo pulito e portabile.

+0

'IPC :: Run' può essere quello che ti serve, piuttosto che il sistema. Oppure, in alternativa, imposta "SIGCHLD" su "IGNORA" in modo che vengano visualizzati automaticamente all'uscita. – Sobrique

+0

Ecco un modo per rilevare se il comando è stato interrotto dall'utente: vedere [Nome del segnale numero 2] (http://stackoverflow.com/questions/29862178/name-of-signal-number-2) –

+0

Vedere anche [Come avviare un processo nel proprio gruppo di processi?] (Http://stackoverflow.com/questions/5809034/in-linux-how-to-start-a-process-in-its-own-process-group- e-more) –

risposta

6

Rendere il bambino la testa di un gruppo di processi, quindi inviare il segnale all'intero gruppo di processi.

#!/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 se $ child_pid;' questo è specifico per Windows? –

+1

No, praticamente il contrario. Windows non ha segnali POSIX o gruppi di processi (anche se 'kill' può essere usato per inviare a un'app console uno dei pochi segnali che Windows ha, Ctrl-C e Ctrl-Break). – ikegami

+0

Allora, che cosa fa negare il cpid? –