2012-09-26 3 views
6

Sto eseguendo un programma in Perl che in un punto valuta i dati in un'istruzione if chiamata da una subroutine, ad es.In Perl esiste un modo per riavviare il programma attualmente in esecuzione da solo?

sub check_good { 
    if (!good) { 
     # exit this subroutine 
     # restart program 
    } 
    else { 
     # keep going 
    } 
} # end sub 

Il problema che ho è con l'uscita e il riavvio. So che posso semplicemente usare exit 0; per uscire direttamente, ma ovviamente questo non è corretto se voglio tornare all'inizio. Ho provato a chiamare la subroutine che essenzialmente avvia il programma, ma ovviamente una volta eseguito tornerà di nuovo su questo punto. Ho pensato di metterlo in un ciclo while, ma ciò significherebbe mettere l'intero file nel loop e sarebbe molto poco pratico.

In realtà non so se questo sia possibile, quindi qualsiasi input sarebbe ottimo.

risposta

8

Se non è stato modificato @ARGV o se ne mantieni una copia, è possibile che si possa fare qualcosa come exec($^X, $0, @ARGV).

$^X and $0 (oppure $EXECUTABLE_NAME e $PROGRAM_NAME, vedere il commento di Brian di seguito) sono l'attuale interprete perl e lo script perl corrente, rispettivamente.

+0

perdona la mia ignoranza - so che @ARGV è usato per gli argomenti della riga di comando, ma ho usato così posso Suppongo che memorizzino i dati nella stessa posizione di memoria (o qualcosa del genere)? – dgBP

+0

Questa è un'asserzione che potresti testare facilmente. – DavidO

+0

Se si utilizza stdin, sarà necessario memorizzarlo da soli, magari in un file temporaneo. – tripleee

-1

Non c'è niente per cui smettere di chiamare system su te stesso. Qualcosa del genere (chiaramente bisognoso di ordine), dove passo un argomento della riga di comando per impedire che il codice si chiami per sempre.

#!/usr/bin/perl 
use strict; 
use warnings; 

print "Starting...\n"; 
sleep 5; 

if (! @ARGV) { 
     print "Start myself again...\n"; 
     system("./sleep.pl secondgo"); 
     print "...and die now\n"; 
     exit; 
} elsif ((@ARGV) && $ARGV[0] eq "secondgo") { 
     print "Just going to die straightaway this time\n"; 
     exit; 
} 
+0

Questa soluzione dipende da un nome file predefinito. Che inizia a succhiare quando abbiamo più link o symlink che puntano a questo script, con nomi diversi. E ciò presuppone ancora che non sia stato eseguito alcun 'chdir' ... Inoltre, stai creando un'intera cascata di processi. Chiamare te stesso una volta non importa, ma ricominciando da solo in questo modo 1000 volte tende a riempire la tabella dei processi e la RAM. – amon

+0

D'accordo con tutti questi punti, stavo solo cercando di dimostrare che è possibile ricominciare da soli. Le risposte di seguito e sopra e chiaramente più complete. –

3

Un'alternativa sarebbe quella di avere sempre due processi: un supervisore e un lavoratore.

Riforma tutta la tua logica in una subroutine chiamata run (o main o qualsiasi altra cosa). Quando la tua logica reale rileva che è necessario riavviarla, dovrebbe uscire con un codice di uscita predefinito diverso da zero (come ad esempio 1).

Allora il vostro script principale e supervisore sarebbe simile a questa:

if (my $worker = fork) { 
    # child process 
    run(@ARGV); 
    exit 0; 
} 
# supervisor process 
waitpid $worker; 
my $status = ($? >> 8); 

if ($status == 1) { ... restart .. } 

exit $status; # propagate exit code... 

Nel semplice scenario in cui si desidera solo per riavviare una volta, questo potrebbe essere un po 'eccessivo. Ma se in qualsiasi momento è necessario essere in grado di gestire altri scenari di errore, questo metodo potrebbe essere preferibile.

Ad esempio se il codice di uscita è 255, ciò indica che lo script principale è chiamato die(). In questo caso, potresti voler implementare una procedura decisionale per riavviare lo script, ignorare l'errore o inoltrare il problema.

Ci sono alcuni moduli su CPAN che implementano tali supervisori. Proc::Launcher è uno di questi e la pagina di manuale include un'ampia discussione di lavori correlati. (Non ho mai usato Proc :: Launcher, è principalmente dovuto a questa discussione che sto collegando ad esso)