2008-12-13 18 views
22

Tengo un script de Perl que necesita ejecutar otro script de Perl. Este segundo script se puede ejecutar directamente en la línea de comandos, pero necesito ejecutarlo desde mi primer programa. Tendré que pasarle algunos parámetros que normalmente se pasarían cuando se ejecute de manera independiente (el primer script se ejecuta periódicamente y ejecuta el segundo script bajo un cierto conjunto de condiciones del sistema).¿Cómo ejecuto un script Perl desde un script Perl?

Las búsquedas preliminares de Google sugieren el uso de palos o una llamada al sistema(). ¿Hay otras formas de ejecutarlo? (Supongo que sí, ya que es Perl de quien estamos hablando: P) ¿Qué método es el preferido si necesito capturar la salida del programa invocado (y, si es posible, canalizar ese resultado mientras se ejecuta a stdout como si fuera el segundo programa fue invocado directamente)?

(Edit:.. Oh, ahora sugiere por lo que algunas preguntas relacionadas This one está cerca, pero no es exactamente lo mismo que lo que estoy preguntando El segundo programa es probable que tomar una hora o más para ejecutar (un montón de I/O), así que no estoy seguro de que una invocación única sea la adecuada para esto.)

Respuesta

28

La ubicación de su intérprete perl actual se puede encontrar en la variable especial $^X. Esto es importante si Perl no está en su camino, o si tiene varias versiones de Perl disponibles, pero para asegurarse de que está utilizando la misma en todos los ámbitos.

Al ejecutar comandos externos, incluidos otros programas Perl, determinar si realmente se ejecutan puede ser bastante difícil. La inspección de $? puede dejar cicatrices mentales duraderos, por lo que prefieren utilizar IPC::System::Simple (disponible desde el CPAN):

use strict; 
use warnings; 
use IPC::System::Simple qw(system capture); 

# Run a command, wait until it finishes, and make sure it works. 
# Output from this program goes directly to STDOUT, and it can take input 
# from your STDIN if required. 
system($^X, "yourscript.pl", @ARGS); 

# Run a command, wait until it finishes, and make sure it works. 
# The output of this command is captured into $results. 
my $results = capture($^X, "yourscript.pl", @ARGS); 

En los dos ejemplos anteriores argumentos que desea pasar a su programa externo entran en @ARGS. El shell también se evita en los dos ejemplos anteriores, lo que le da una pequeña ventaja de velocidad y evita cualquier interacción no deseada que involucre metacaracteres del shell. El código anterior también espera que su segundo programa devuelva un valor de salida cero para indicar el éxito; Si ese no es el caso, se puede especificar un primer argumento adicional de los valores de salida permisibles:

# Both of these commands allow an exit value of 0, 1 or 2 to be considered 
# a successful execution of the command. 

system([0,1,2], $^X, "yourscript.pl", @ARGS); 
# OR 
capture([0,1,2, $^X, "yourscript.pl", @ARGS); 

Si usted tiene un proceso de larga duración y desea procesar sus datos mientras que se está generando, entonces' Probablemente va a necesitar un canal abierto, o uno de los módulos IPC más pesados ​​del CPAN.

Habiendo dicho todo esto, cada vez que necesite llamar a otro programa Perl de Perl, puede considerar si usar un módulo sería una mejor opción. Iniciar otro programa conlleva bastantes gastos generales, tanto en términos de costos iniciales como de costos de E/S para mover datos entre procesos. También aumenta significativamente la dificultad de manejo de errores. Si puede convertir su programa externo en un módulo, puede encontrar que simplifica su diseño general.

Todo lo mejor,

Paul

6

Utilice los trazos si necesita capturar la salida del comando.

Utilice system si no necesita capturar la salida del comando.

TMTOWTDI: entonces hay otras formas también, pero esas son las dos más fáciles y las más probables.

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

open(OUTPUT, "date|") or die "Failed to create process: $!\n"; 

while (<OUTPUT>) 
{ 
    print; 
} 

close(OUTPUT); 

print "Process exited with value " . ($? >> 8) . "\n"; 

Esto iniciará el proceso de date y canalizar la salida del comando al gestor de archivo de salida que puede procesar una línea a la vez. Cuando el comando finaliza, puede cerrar el identificador de archivo de salida y recuperar el valor de retorno del proceso. Reemplace date con lo que quiera.

3

Si necesita llamar a su forma asíncrona script externo -usted sólo quieren poner en marcha y no esperar a que se ACABADO, entonces:

# On Unix systems, either of these will execute and just carry-on 
# You can't collect output that way 
`myscript.pl &`; 
system ('myscript.pl &');  

# On Windows systems the equivalent would be 
`start myscript.pl`; 
system ('start myscript.pl'); 

# If you just want to execute another script and terminate the current one 
exec ('myscript.pl'); 
9

puedo pensar en algunas maneras de hacer esto. Ya mencionaste los dos primeros, así que no entraré en detalles sobre ellos.

  1. backticks: $ retVal = `` perl somePerlScript.pl ;
  2. llamada system()
  3. eval

El eval se puede lograr por sorber el otro archivo en una cadena (o una lista de cadenas), luego 'eval'ing las cuerdas. Aquí hay una muestra:

#!/usr/bin/perl 
open PERLFILE, "<somePerlScript.pl"; 
undef $/; # this allows me to slurp the file, ignoring newlines 
my $program = <PERLFILE>; 
eval $program; 

4. do:

do 'somePerlScript.pl'

+0

¿No sería mucho más fácil y más conciso simplemente usar 'do'? – innaM

+0

Gracias. Agregué 'do' a la lista. – Colin

4

Consulte la documentación de perlipc para obtener varias opciones de comunicación entre procesos.

Si su primer script simplemente configura el entorno para el segundo script, es posible que esté buscando exec.

9

Ya tiene buenas respuestas a su pregunta, pero siempre existe la posibilidad de adoptar un punto de vista diferente: tal vez debería considerar refactorizar la secuencia de comandos que desea ejecutar desde el primer script.Convierta la funcionalidad en un módulo. Use el módulo del primer guión y del segundo guión.

+0

Lo consideré hace un tiempo, pero lo cancelé por dos razones. Primero, otro desarrollador está trabajando en el segundo programa, y ​​segundo, el segundo fue terminado hace meses, y se pensó en este primer script para automatizarlo. Si volviera a hacer esto, probablemente haría módulos. – cbowns

23

Usted puede simplemente hacer ella.

{ 
    local @ARGV = qw<param1 param2 param3>; 
    do '/home/buddy/myscript.pl'; 
} 

Impide la sobrecarga de la carga en otra copia de perl.

0

Quería hacer algo como esto para descargar no subrutinas en un archivo externo para facilitar la edición. De hecho, hice esto en una subrutina. La ventaja de esta forma es que esas "mis" variables en el archivo externo se declaran en el espacio de nombres principal. Si usa 'do', aparentemente no migran al espacio de nombres principal. Tenga en cuenta que la presentación a continuación no incluye el manejo de errores

sub getcode($) { 
    my @list; 
    my $filename = shift; 
    open (INFILE, "< $filename"); 
    @list = <INFILE>; 
    close (INFILE); 
    return \@list; 
} 

# and to use it: 

my $codelist = []; 
$codelist = getcode('sourcefile.pl'); 
eval join ("", @$codelist); 
Cuestiones relacionadas