-+  Associazione
-+  Documenti
 |-  Modern Perl
 |-  Bibliografia
 |-  Articoli
 |-  Talk
 |-  Perlfunc
 |-  F.A.Q.
 |-  F.A.Q. iclp
-+  Eventi
-+  Community
-+  Blog
-+  Link
Corso di Perl



 


indietro

[25] Come posso catturare STDERR da un comando esterno?

Ci sono tre modi principali per lanciare comandi esterni:

    system $cmd;            # usando system()
    $output = `$cmd`;       # usando i backtick (``)
    open (PIPE, "cmd |");   # usando open()

Con system(), sia STDOUT che STDERR andranno a finire nello stesso posto in cui andranno a finire lo STDOUT e lo STDERR dello script, a meno che il comando passato a system() non li rediriga. I backtick e open() leggono soltanto lo STDOUT del vostro comando.

Potete anche usare la funzione open3() da IPC::Open3. Benjamin Goldberg ha fornito del codice di esempio:

Per catturare lo STDOUT di un programma, ma scartare il suo STDERR:

    use IPC::Open3;
    use File::Spec;
    use Symbol qw(gensym);
    open(NULL, ">", File::Spec->devnull);
    my $pid = open3(gensym, \*PH, ">&NULL", "cmd");
    while( <PH> ) { }
    waitpid($pid, 0);

Per catturare lo STDERR di un programma, ma scartare il suo STDOUT:

    use IPC::Open3;
    use File::Spec;
    use Symbol qw(gensym);
    open(NULL, ">", File::Spec->devnull);
    my $pid = open3(gensym, ">&NULL", \*PH, "cmd");
    while( <PH> ) { }
    waitpid($pid, 0);

Per catturare lo STDERR di un programma e far sì che il suo STDOUT vada sul nostro STDERR:

    use IPC::Open3;
    use Symbol qw(gensym);
    my $pid = open3(gensym, ">&STDERR", \*PH, "cmd");
    while( <PH> ) { }
    waitpid($pid, 0);

Per leggere sia lo STDOUT di un comando che il suo STDERR separatamente, potete redirezionarli su file temporanei, lasciare che il comando venga eseguito poi leggete i file temporanei:

    use IPC::Open3;
    use Symbol qw(gensym);
    use IO::File;
    local *CATTURAOUT = IO::File->new_tmpfile;
    local *CATTURAERR = IO::File->new_tmpfile;
    my $pid = open3(gensym, ">&CATTURAOUT", ">&CATTURAERR", "cmd");
    waitpid($pid, 0);
    seek $_, 0, 0 for \*CATTURAOUT, \*CATTURAERR;
    while( <CATTURAOUT> ) {}
    while( <CATTURAERR> ) {}

Ma non c'è un vero motivo affinché *entrambi* siano dei file temporanei... quello che segue dovrebbe funzionare allo stesso modo, senza deadlock:

    use IPC::Open3;
    use Symbol qw(gensym);
    use IO::File;
    local *CATTURAERR = IO::File->new_tmpfile;
    my $pid = open3(gensym, \*CATTURAOUT, ">&CATTURAERR", "cmd");
    while( <CATTURAOUT> ) {}
    waitpid($pid, 0);
    seek CATTURAERR, 0, 0;
    while( <CATTURAERR> ) {}

E sarà anche più veloce, visto che possiamo iniziare ad elaborare immediatamente lo stdout del programma, piuttosto che aspettare che il programma finisca.

Con ciascuno di questi, potete modificare il descrittore di file prima della chiamata:

    open(STDOUT, ">logfile");
    system("ls");

oppure potete usare la redirezione dei descrittori di file della Bourne shell.

    $output = `$cmd 2>un_qualche_file`;
    open (PIPE, "cmd 2>un_qualche_file |");

Potete anche usare la redirezione dei descrittori di file per rendere STDERR un duplicato di STDOUT:

    $output = `$cmd 2>&1`;
    open (PIPE, "cmd 2>&1 |");

Notate che non si può semplicemente aprire STDERR affinché diventi, nel vostro programma, un duplicato di STDOUT, evitando di fare ricorso alla shell per effetturare la redirezione. Questo non funziona:

    open(STDERR, ">&STDOUT");
    $output_completo = `cmd args`;  # stderr continua a sfuggire

Questo fallisce perché open() fa in modo che STDERR vada a finire dove andava a finire STDOUT al momento della chiamata a open(). I backtick poi fanno in modo che solo STDOUT vada a finire in una stringa, ma non modificano STDERR (che continua ad andare laddove andava il vecchio STDOUT).

Notate che per la redirezione, nei backtick, si deve usare la sintassi della Bourne shell (sh(1)), non quella di csh(1)! Dettagli sul perché la funzione system(), i backtick e le aperture di pipe usino tutte la Bourne shell stanno nell'articolo versus/csh.whynot della collezione "Far More Than You Ever Wanted To Know" ["Molto più di quello che avete sempre voluto sapere sul Perl", NdT] reperibile all'url http://www.cpan.org/misc/olddoc/FMTEYEWTK.tgz . Per catturare allo stesso tempo lo STDOUT e lo STDERR di un comando:

    $output = `cmd 2>&1`;           # con i backtick
    $pid = open(PH, "cmd 2>&1 |");  # o con una pipe
    while (<PH>) { }                #    con relativa lettura

Per catturare lo STDOUT di un comando, buttando via il suo STDERR:

    $output = `cmd 2>/dev/null`;           # con i backtick
    $pid = open(PH, "cmd 2>/dev/null |");  # o con una pipe
    while (<PH>) { }                       #    con relativa lettura

Per catturare lo STDERR di un comando, buttando via il suo STDOUT:

    $output = `cmd 2>&1 1>/dev/null`;           # con i backtick
    $pid = open(PH, "cmd 2>&1 1>/dev/null |");  # o con una pipe
    while (<PH>) { }                            #    con relativa lettura

Per scambiare lo STDOUT e lo STDERR di un comando, con lo scopo di catturarne lo STDERR lasciando che il suo STDOUT si sostituisca al nostro STDERR:

    $output = `cmd 3>&1 1>&2 2>&3 3>&-`;        # con i backtick
    $pid = open(PH, "cmd 3>&1 1>&2 2>&3 3>&-|");# o con una pipe
    while (<PH>) { }                            #    con relativa lettura

Per leggere lo STDOUT e lo STDERR di un comando separatamente, è più facile redirigerli su file separatamente, e poi leggere da questi file quando il programma è terminato:

    system("programma args 1>programma.stdout 2>programma.stderr");

L'ordine è importante in tutti questi esempi, poiché la shell processa le redirezioni di descrittori di file rigorosamente da sinistra a destra.

    system("prog args 1>tmpfile 2>&1");
    system("prog args 2>&1 1>tmpfile");

Il primo comando manda sia lo standard out che lo standard error in un file temporaneo. Il secondo comando manda nel file solo il vecchio standard output, e il vecchio standard error finisce soltanto nel vecchio standard out.

vedi in inglese

AUTORE E COPYRIGHT

Copyright (c) 1997, 1998, 1999, 2000, 2001 Tom Christiansen e Nathan Torkington. Tutti i diritti riservati.

Questa documentazione è libera; puoi ridistribuirla e/o modificarla secondo gli stessi termini applicati al Perl.

Indipendentemente dalle modalitè di distribuzione, tutti gli esempi di codice in questo file sono rilasciati al pubblico dominio. Potete, e siete incoraggiati a farlo, utilizzare il presente codice o qualunque forma derivata da esso nei vostri programmi per divertimento o per profitto. Un semplice commento nel codice che dia riconoscimento alle FAQ sarebbe cortese ma non è obbligatorio.

D:
Progetti e documenti in rilievo
Corso di Perl Progetto pod2it
D:
La ML di Perl.it
mongers@perl.it è la lista ufficiale di Perl Mongers Italia per porre quesiti di tipo tecnico, per rimanere aggiornato su meeting, incontri, manifestazioni e novità su Perl.it.
Iscriviti!
D:
Annunci Google