Come posso eseguire uno script Perl all’interno di uno script Perl?

Ho uno script Perl che deve eseguire un altro script Perl. Questo secondo script può essere eseguito direttamente sulla riga di comando, ma ho bisogno di eseguirlo dal mio primo programma. Avrò bisogno di passare alcuni parametri che normalmente dovrebbero essere passati quando è eseguito in modo autonomo (il primo script viene eseguito periodicamente ed esegue il secondo script in un determinato insieme di condizioni di sistema).

Le ricerche preliminari su Google suggeriscono di utilizzare i backtick o una chiamata system (). Ci sono altri modi per eseguirlo? (Sto indovinando si, visto che è Perl di cui stiamo parlando: P) Quale metodo è preferibile se ho bisogno di catturare l’output dal programma invocato (e, se ansible, pipe che viene emesso mentre viene eseguito su stdout come se il secondo il programma è stato invocato direttamente)?

(Modifica: oh, ora SO suggerisce alcune domande correlate: questa è vicina, ma non esattamente uguale a quella che sto chiedendo.Il secondo programma richiederà probabilmente un’ora o più per essere eseguito (un sacco di I / O), quindi Non sono sicuro che un’invocazione una tantum sia la soluzione giusta per questo.)

La posizione del tuo attuale interprete perl può essere trovata nella variabile speciale $^X Questo è importante se perl non è nel tuo percorso, o se hai più versioni perl disponibili ma per assicurarti di utilizzare lo stesso su tutta la linea.

Quando si eseguono comandi esterni, inclusi altri programmi Perl, determinare se sono effettivamente eseguiti può essere piuttosto difficile. Ispezionando $? può lasciare cicatrici mentali durature, quindi preferisco usare IPC :: System :: Simple (disponibile dal 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); 

In entrambi gli esempi precedenti, qualsiasi argomento che desideri passare al tuo programma esterno va in @ARGS . La shell è anche evitata in entrambi gli esempi sopra, che offre un piccolo vantaggio di velocità ed evita qualsiasi interferenza indesiderata che coinvolga i meta-caratteri della shell. Il codice precedente prevede inoltre che il secondo programma restituisca un valore di uscita pari a zero per indicare il successo; in caso contrario, è ansible specificare un primo argomento aggiuntivo dei valori di uscita consentiti:

  # 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 ); 

Se si dispone di un processo di lunga durata e si desidera elaborare i dati mentre viene generato, è probabile che sia necessario un piped aperto o uno dei moduli IPC più pesanti dal CPAN.

Detto questo, ogni volta che devi chiamare un altro programma Perl da Perl, potresti voler considerare se usare un modulo sarebbe una scelta migliore. L’avvio di un altro programma comporta un certo numero di spese generali, sia in termini di costi di avviamento che di costi di I / O per lo spostamento dei dati tra i processi. Aumenta anche significativamente la difficoltà di gestione degli errori. Se puoi trasformare il tuo programma esterno in un modulo, potresti trovarlo che semplifica la tua progettazione generale.

Ti auguro il meglio,

Paolo

Puoi farlo e basta

 { local @ARGV = qw; do '/home/buddy/myscript.pl'; } 

Impedisce il sovraccarico del caricamento in un’altra copia di perl.

Hai già delle buone risposte alla tua domanda, ma c’è sempre la possibilità di prendere un altro punto di vista: forse dovresti prendere in considerazione il refactoring dello script che vuoi eseguire dal primo script. Trasforma la funzionalità in un modulo. Usa il modulo dal primo e dal secondo script.

Posso pensare ad alcuni modi per farlo. Hai già menzionato i primi due, quindi non entrerò nei dettagli su di essi.

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

L’eval può essere eseguita slurping l’altro file in una stringa (o un elenco di stringhe), quindi ‘eval’ing le stringhe. Ecco un esempio:

 #!/usr/bin/perl open PERLFILE, "; eval $program; 

4. fare:

  fai 'somePerlScript.pl' 

Utilizzare i backtick se è necessario acquisire l’output del comando.

Utilizzare il system se non è necessario acquisire l’output del comando.

TMTOWTDI: quindi ci sono anche altri modi, ma quelli sono i due più facili e più probabili.

Se hai bisogno di chiamare in modo asincrono lo script esterno: vuoi solo avviarlo e non aspettare che finisca-, allora:

 # 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'); 

Vedere la documentazione perlipc per diverse opzioni per la comunicazione tra processi.

Se il tuo primo script imposta semplicemente l’ambiente per il secondo script, potresti cercare exec .

 #!/usr/bin/perl use strict; open(OUTPUT, "date|") or die "Failed to create process: $!\n"; while () { print; } close(OUTPUT); print "Process exited with value " . ($? >> 8) . "\n"; 

Ciò avvierà la date del processo e condurrà l’output del comando al filehandle OUTPUT che è ansible elaborare una linea alla volta. Al termine del comando, è ansible chiudere il filehandle di output e recuperare il valore di ritorno del processo. Sostituisci la date con quello che vuoi.

Volevo fare qualcosa di simile per scaricare le non-subroutine in un file esterno per rendere più facile la modifica. In realtà l’ho trasformato in una subroutine. Il vantaggio di questo modo è che quelle “mie” variabili nel file esterno vengono dichiarate nello spazio dei nomi principale. Se si usa ‘do’, apparentemente non migrano allo spazio dei nomi principale. Nota la presentazione qui sotto non include la gestione degli errori

 sub getcode($) { my @list; my $filename = shift; open (INFILE, "< $filename"); @list = ; close (INFILE); return \@list; } # and to use it: my $codelist = []; $codelist = getcode('sourcefile.pl'); eval join ("", @$codelist);