2012-09-26 18 views
6

Estoy ejecutando un programa en Perl que en un momento evalúa datos en una instrucción if llamada desde una subrutina, p.En Perl, ¿hay alguna manera de reiniciar el programa que se ejecuta desde sí mismo?

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

El problema que tengo es salir y reiniciar. Sé que puedo usar exit 0; para salir directamente, pero obviamente esto no es correcto si quiero volver al principio. Traté de llamar a la subrutina que esencialmente inicia el programa, pero, por supuesto, una vez que se ha ejecutado volverá a este punto nuevamente. Pensé en ponerlo en un ciclo while, pero esto significaría poner el archivo completo en el bucle y sería muy poco práctico.

Realmente no sé si esto es posible, por lo que cualquier entrada sería genial.

Respuesta

8

Si no ha cambiado @ARGV, o tiene una copia, posiblemente podría hacer algo como exec($^X, $0, @ARGV).

$^X and $0 (o $EXECUTABLE_NAME y $PROGRAM_NAME, consulte el comentario de Brian a continuación) son el intérprete perl actual y el guión perl actual, respectivamente.

+0

perdón mi ignorancia - Sé que @ARGV se utiliza para argumentos de línea de comandos, pero he usado para que pueda Supongo que almacenan datos en la misma ubicación de memoria (o algo así). – dgBP

+0

Esa es una afirmación que podría probar fácilmente. – DavidO

+0

Si consume stdin, tendrá que almacenarlo usted mismo, quizás en un archivo temporal. – tripleee

-1

No hay nada que lo impida llamar a sí mismo system. Algo así (claramente necesita una ordenada), donde paso un argumento de línea de comandos para evitar que el código se llame a sí mismo para siempre.

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

Esta solución depende de un nombre de archivo predeterminado. Eso comienza a apestar cuando tenemos múltiples enlaces o enlaces simbólicos que apuntan a este script, bajo diferentes nombres. Y eso sigue suponiendo que no se realizó 'chdir' ... Además, está creando una cascada de procesos. Llamarte a ti mismo una vez no importará, pero reiniciarte de esta manera 1000 veces tiende a llenar la mesa de proceso y la RAM. – amon

+0

De acuerdo con todos esos puntos, solo estaba tratando de demostrar que es posible reiniciar usted mismo. Las respuestas abajo y arriba y claramente más comprensivas. –

3

Una alternativa sería tener siempre dos procesos: un supervisor y un trabajador.

Refactorice toda su lógica en una subrutina llamada run (o main o lo que sea). Cuando su lógica real detecta que necesita reiniciarse, debe salir con un código de salida predefinido distinto de cero (como 1, por ejemplo).

A continuación, el script principal y el supervisor se vería así:

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... 

En el sencillo escenario en el que sólo desea reiniciar una vez, esto podría ser un poco excesivo. Pero si en algún momento necesita ser capaz de manejar otros escenarios de error, este método podría ser preferible.

Por ejemplo, si el código de salida es 255, esto indica que el script principal se llamaba die(). En este caso, es posible que desee implementar algún procedimiento de decisión para reiniciar el script, ignorar el error o escalar el problema.

Existen bastantes módulos en CPAN que implementan dichos supervisores. Proc::Launcher es uno de ellos y la página del manual incluye una extensa discusión de trabajos relacionados. (Nunca he usado Proc :: Launcher, es principalmente debido a esta discusión que estoy vinculando a ella)

Cuestiones relacionadas