Sei sulla pagina 1di 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
Capita a volte di voler redirigere l'output di un programma su un file, o da qualche altra parte.
Altre volte, invece, vorremmo che gli input arrivassero da dove diciamo noi, invece che da dove il
programma pensa che stiano arrivando. A volte, infine, abbiamo bisogno che queste redirezioni
siano temporanee, e dopo un po' vogliamo ``tornare indietro''. Vediamo un po' come fare.

I Flussi Standard
In un programma avete a disposizione tre flussi di input/output detti standard (proprio perch ve li
ritrovate sempre):

stdin
da dove il programma prende i suoi ingressi, normalmente associato alla tastiera;

stdout
dove il programma invia le sue uscite, normalmente associato al terminale;

stderr
dove il programma invia messaggi di errore, che segnalano una condizione anomala ma
che non fanno parte delle uscite. Anche questo, normalmente, associato al terminale.
Nel mondo Unix (sinceramente sono un po' all'oscuro del mondo Windows) questi flussi standard
sono associati a dei descrittori di file, che sono degli indici numerici interi che che il sistema
operativo utilizza per individuare i vari canali di I/O di un processo. In particolare, stdin sempre
associato al descrittore 0, stdout al descrittore 1 e stderr al descrittore 2.
Chiunque abbia giocato un po' con qualcosa di somigliante ad una shell Unix sa che quelle
``associazioni'' di default a tastiera e terminale possono essere aggirate con facilit utilizzando
pipe (con il carattere | a separare due chiamate a due programmi differenti, ove lo stdout di
quello a sinistra viene collegato allo stdin di quello a destra) e redirezioni su file (con il caratteri <
per legare stdin ad un file, e > per legare stdout ad un file). Se volete saperne di pi l'ottima
pagina di manuale della shell (sto pensando a bash) sapr soddisfare tutte le vostre curiosit.
Qui per non ci poniamo il problema di come fare queste redirezioni da fuori, ma di come farle da
dentro al nostro programma in Perl. Nel seguito non parleremo quasi pi di stderr, comunque, visto
Perl Mongers Italia. Tutti i diritti riservati.

1 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
che le considerazioni per stdout possono essere applicate (quasi) per intero.

I Flussi Standard In Perl


I flussi standard in Perl sono rappresentati da tre filehandle dai nomi poco sorprendenti (ma in
lettere maiuscole, attenzione!): STDIN, STDOUT e STDERR. (Ok, in realt probabilmente potrete
utilizzare anche le lettere minuscole, ma non lo fate.)
I flussi standard in Perl si usano come qualsiasi altro filehandle:
my $un_input = <STDIN>;
print STDOUT "Ciao, Mondo!\n";
print STDERR "Ooops, hai commesso un errore!\n";

Se non mettete nessun filehandle in una print si va per default su STDOUT:


print "Ciao, Mondo!\n";

# va su standard output

appena il caso di dire che una delle ``best practice'' predicate da Damian Conway (autore
emerito in ambito Perl) quella di usare un costrutto un po' pi involuto per dire su quale
filehandle vogliamo stampare:
print {*STDOUT} "Ciao, Mondo!\n";

# fa quello che ci si aspetta

ma stiamo veramente divagando.


Va osservata una differenza fra filehandle e descrittori:
un descrittore un indice condiviso fra processo e sistema operativo per effettuare
operazioni di I/O (in particolare, un indice che punta ad un elemento di una tabella dei file
che il sistema operativo tiene per il dato processo);
un filehandle uno ``strumento'' a disposizione del programmatore per istruire il processo
sulle operazioni di I/O da effettuare, che include anche possibili operazioni avanzate come
buffering, encoding ecc.
Ovviamente i due concetti sono fortemente correlati fra loro: un filehandle una specie di mantello
intorno al descrittore; alla fin fine quando il processo decide di effettuare l'I/O utilizza proprio il
descrittore associato al filehandle. Per impicciarci su questa associazione possiamo utilizzare la
funzione fileno():
my $descrittore = fileno $filehandle;
Perl Mongers Italia. Tutti i diritti riservati.

2 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
Definiamo allora una piccola funzione che ci torner utile nel seguito per cercare di capire cosa
succede:
sub stampa_descrittore {
my ($nome, $filehandle) = @_;
print {*STDERR} "$nome ha descrittore ", fileno($filehandle), "\n";
}
stampa_descrittore(STDIN => \*STDIN);
# STDIN ha descrittore 0
stampa_descrittore(STDOUT => \*STDOUT); # STDOUT ha descrittore 1
stampa_descrittore(STDERR => \*STDERR); # STDERR ha descrittore 2

Perch Redirigere, Poi?


Beh, questo veramente fuori dall'ambito di questo articolo, non vi pare? Se non vi interessa, che
ve lo leggete a fare?
Scherzi a parte, potrebbero esserci molti motivi per fare una cosa del genere. Un primo esempio
il seguente: avete un programma gi fatto, e volete aggiungere un'opzione di chiamata per cui le
uscite vanno su file anzich su terminale. Come fare? Una soluzione stabilire, all'inizio del
programma, quale debba essere il filehandle di uscita, dipendentemente dalle opzioni che vi sono
state passate, qualcosa tipo:
my $output;
if (exists $opzioni{output}) {
open $output, '>', $opzioni{output}
or die "open('$opzioni{output}'): $!";
}
else {
$output = \*STDOUT;
}

A questo punto $output dovrebbe essere usato tutte le volte che volete stampare un'uscita del
programma.

Come?!?!? Devo cambiare tutte le uscite?!?


Beh, con questa tecnica s, magari era meglio pensarci prima. Altrimenti, potreste redirigere
STDOUT sul file e non cambiare una virgola. Un po' meno pulito, forse, ma efficace.
Un altro caso in cui questa redirezione risulta utile quando volete chiamare un programma
esterno che - senza che ci sorprendiamo troppo - prende i suoi ingressi dal proprio stdin e
manda le uscite sul proprio stdout. Ci sono mille modi per chiamare un programma esterno in
Perl, ma se siete per qualche motivo costretti ad usare ``il vecchio sistema'' di pipe()/fork()
Perl Mongers Italia. Tutti i diritti riservati.

3 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
allora dovrete fare un po' di redirezioni prima di chiamare il programma esterno, sulla falsariga di
quanto segue:
my ($figlio_r, $figlio_w, $padre_r, $padre_w);
pipe($figlio_r, $padre_w);
pipe($padre_r, $figlio_w);
defined(my $pid = fork()) or die "fork(): $!";
if ($pid) { # padre
close $figlio_r;
close $figlio_w;
# ... dialoga con il figlio utilizzando:
#
$padre_r per leggere dal figlio
#
$padre_w per scrivere al figlio
}
else {
# figlio
close $padre_r;
close $padre_w;
# dobbiamo capire come fare:
# REDIRIGI STDIN su $figlio_r
# REDIRIGI STDOUT su $figlio_w
exec {$programma} $programma, @ARGOMENTI
or die "exec('$programma'): $!";
}

Le Uova Di Colombo
Il sistema pi semplice per redirigere uno dei filehandle standard in Perl (anzi, forse l'unico vero
modo, come avremo modo di vedere pi avanti) ri-aprire il filehandle su qualcosa di differente.
In questo ci viene in aiuto la funzione open(), ovviamente: con cosa pensavate di aprire un
filehandle?

Su File
Il livello pi base di redirezione piuttosto semplice. Se infatti l'obiettivo quello di redirigere su
file, baster ri-aprire il filehandle sul file relativo:
open STDIN, '<', $file_input or die "open('$file_input'): $!";
open STDOUT, '>', $file_input or die "open('$file_input'): $!";

Per redirigere su file non avete bisogno di chiudere il filehandle prima della nuova open(), perch
Perl lo far automaticamente per voi.
Funziona ed semplice, ma non sempre dovremo redirigere su un file, o su un file che dobbiamo
Perl Mongers Italia. Tutti i diritti riservati.

4 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
ancora aprire. Forse il caso di andare avanti.

Su Una Variabile
A partire da Perl 5.8.x possibile aprire un filehandle che punta ad una variabile in memoria invece
che da qualche altra parte. Per fare questa cosa meravigliosa basta passare, al posto del nome del
file, un riferimento alla variabile da aprire:
my $variabile;
open my $fh, '>', \$variabile or die "open(): $!";

Inutile dirlo, la redirezione dei flussi standard funziona anche in questo caso, esattamente come
descritto per un normale file nella sezione precedente. L'unica avvertenza per la seguente: per
redirigere un filehandle di output (STDOUT o STDERR) sar prima necessario chiuderlo:
close STDOUT;
open STDOUT, '>', \$variabile or die "open('$file_input'): $!";

Questa tecnica pu risultare particolarmente comoda quando avete un pezzo di codice


preesistente, o anche un modulo, che stampano le proprie uscite su STDOUT, ma voi volete
catturare queste uscite per potervele ``lavorare'' prima di stamparle effettivamente per farle
vedere agli utenti del programma (ad esempio, se volete aggiungere dei numeri di riga, oppure
eliminare tutte le parolacce dal testo). Attenzione che, in questo caso, dovete anche tenere una
ciambella di salvataggio verso la vera uscita del programma, altrimenti dopo aver effettuato la
redirezione non saprete pi come comunicare con l'utente. Come farlo... sar evidente nel seguito
(i pi curiosi possono saltare subito alla fine dell'articolo, proprio prima delle conclusioni).

Su Filehandle: Un Buco Nell'Acqua (O Quasi)


In qualche modo - da un modulo bellissimo che avete appena trovato, o per sola imposizione delle
mani - vi ritrovate un filehandle che vorreste sostituire ad uno dei flussi standard.
Il metodo pi semplice che pu venire in mente far ``puntare'' i filehandle dove vogliamo noi. I
filehandle standard ``vivono'' nel pacchetto main, in dei GLOB che hanno lo stesso nome (no, non
vi tedier spiegando cos' un GLOB, tranquilli). In maniera molto cruda, possiamo fare qualcosa
del genere:
*STDIN = $filehandle_nuovo_input;
*STDOUT = $filehandle_nuovo_output;

Cominciamo subito a dire che questo approccio funziona:


Perl Mongers Italia. Tutti i diritti riservati.

5 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
open my $fh, '>', 'prova.txt' or die "open(): $!";
*STDOUT = $fh;
# Redirezione!
print "Ciao, Mondo!\n";
# stampa su prova.txt

Per casi molto semplici pu andare bene, anche se probabilmente non vi guarderanno molto bene
se fate qualcosa del genere. In particolare, occorre prestare attenzione al fatto che questa
operazione snatura i flussi, dissociandoli dal loro significato di ``flussi standard'' che hanno a livello
di sistema operativo. Che significa? Ci arriviamo subito, basta vedere cosa sta succedendo in
basso, sui descrittori:
open my $fh, '>', 'prova.txt' or die "open(): $!";
stampa_descrittore(STDOUT => \*STDOUT); # STDOUT ha descrittore 1
stampa_descrittore(fh
=> $fh);
# fh ha descrittore 3
*STDOUT = $fh;
# Redirezione!
stampa_descrittore(STDOUT => \*STDOUT); # STDOUT ha descrittore 3
print "Ciao, Mondo!\n";
# stampa su prova.txt

Attenzione! STDOUT ha cambiato descrittore! come se avessimo tolto il mantello con scritto
STDOUT dal descrittore standard numero 1 e l'avessimo avvolto intorno al descrittore numero 3.
Per il codice la chiamata a print() continua ad essere diretta su STDOUT, ma per il sistema
operativo le chiamate di I/O sono rivolte al descrittore 3, che punta al file e non il descrittore
standard per l'output.
Quanto pu importarci di questa cosa? Dipende. Se l'obiettivo era unicamente redirigere le varie
print() nel programma, questo approccio se la cava egregiamente. Ma se vogliamo fare la
redirezione per poi chiamare un altro programma con exec() questo sistema fallir miseramente,
perch in fase di esecuzione del nuovo programma i descrittori considerati per i flussi standard
sono sempre 0, 1 e 2, e questi coincidono con quelli del processo prima della chiamata ad
exec()!

Su Filehandle: Come Fare Veramente


Ci sar pure un sistema, allora? Ebbene s, il sistema c' ed fare in modo da non cambiare il
descrittore di STDOUT. Lapalissiano? Forse. Ricordate quando s' detto che - probabilmente l'unico modo per effettuare una redirezione come si deve usare open()? il momento di
mettere alla prova quell'affermazione.
La funzione open() ha circa 2000 varianti, ed una di queste utilizzata per chiamare la
sottostante funzione di sistema dup(), che clona gli elementi nella tabella dei file gestita dal
sistema operativo:
Perl Mongers Italia. Tutti i diritti riservati.

6 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
open my $fh, '>', 'prova.txt' or die "open(): $!";
stampa_descrittore(STDOUT => \*STDOUT); # STDOUT ha descrittore 1
stampa_descrittore(fh
=> $fh);
# fh ha descrittore 3
open STDOUT, '>&', $fh or die "dup/open(): $!"; # Redirezione!
stampa_descrittore(STDOUT => \*STDOUT); # STDOUT ha descrittore 1
print "Ciao, Mondo!\n";
# stampa su prova.txt

Benissimo, quindi! Mettendo il carattere di e commerciale & dopo il carattere che indica la modalit
di apertura possiamo fare una redirezione a prova di exec()! Una redirezione dello STDIN
sarebbe dunque:
open STDIN, '<&', $filehandle_nuovo_input
or die "dup/open(): $!";

Come detto, dup() lavora a livello di tabella dei file nel sistema operativo: in pratica non fa altro
che copiare un elemento di una tabella in un altro elemento. In questo modo, entrambi gli
elementi puntano verso lo stesso flusso - sia esso un file su disco, un socket per una
comunicazione in rete, o qualsiasi altra cosa sia rappresentata da un file in senso esteso - pur
avendo sorti ormai slegate: se chiudo uno dei due, l'altro rimane vivo e vegeto.

Moduli Poco Rispettosi


Che succede se un modulo che vogliamo utilizzare non si attiene alla forma pulita ed effettua
redirezioni alla buona? Non una domanda oziosa per allungare un po' il brodo di questo articolo,
ma anzi il motivo principale per cui mi venuto in mente di scriverlo!

Un Primo Tentativo
La prima cosa che mi venuta in mente quando ho avuto questo problema (con
HTTP::Server::Simple) stato fare qualcosa di questo tipo:
# Ad inizio programma, quando i filehandle sono ancora "intatti"
my $STDIN_originale = \*STDIN;
# ...
# Ad un certo punto il modulo far qualcosa del genere:
*STDIN = $nuovo_input;
# ...
# ...
# Nel programma, allora, proviamo ad invertire
my $STDIN_nuovo = \*STDIN;
*STDIN = $STDIN_originale;
# TENTATIVO di ripristino
open STDIN, '<&', $STDIN_nuovo; # redirezione corretta
Perl Mongers Italia. Tutti i diritti riservati.

7 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
Peccato che non funzioni! Il problema che $STDIN_originale non slegata da STDIN, ma
anzi ne segue le sorti molto da vicino, visto che la ``punta'' direttamente. In poche parole, la
redirezione fatta ``alla buona'' modifica anche $STDIN_originale, vanificando il nostro
tentativo di ``conservazione'':
# Ad inizio programma, quando i filehandle sono ancora "intatti"
my $STDIN_originale = \*STDIN;
stampa_descrittore(STDIN_originale => $STDIN_originale); # stampa:
# STDIN_originale ha descrittore 0
# ...
# Ad un certo punto il modulo far qualcosa del genere:
*STDIN = $nuovo_input;
stampa_descrittore(STDIN => \*STDIN); # STDIN ha descrittore 3
# ...
# ...
stampa_descrittore(STDIN_originale => $STDIN_originale); # stampa:
# STDIN_originale ha descrittore 3

Un Altro Tentativo
Dobbiamo trovare un altro modo per conservare il filehandle originale, quindi. Da notare che una
semplice redirezione dup() non andrebbe bene:
open my $copia, '<&', \*STDIN
or die "dup/open(): $!";
stampa_descrittore(copia => $copia); # copia ha descrittore 3

Pensandoci a posteriori, abbastanza chiaro (o almeno a me risultato chiaro solo pensandoci a


posteriori). dup() effettua una copia, a livello di tabella dei file del processo (gestita dal sistema
operativo), da un certo descrittore a un altro descrittore. In questo caso, $copia una variabile
inizialmente undef, per cui - dietro le quinte - per prima cosa $copia viene creata come
filehandle, cui associato un descrittore non utilizzato (3 nell'esempio), poi viene effettuata la
copia dal descrittore 0 a quello di $copia.
Non tutto il male viene per nuocere: a questo punto $copia pu diventare la nostra ``memoria
storica'' dell'input originale del processo, e pu giocare (come vedremo) un ruolo fondamentale se
dovessimo averne di nuovo bisogno. Ma non anticipiamo troppo, e torniamo al nostro problema
originale: non perdere il nostro aggancio al descrittore standard.

Una Soluzione
Perl Mongers Italia. Tutti i diritti riservati.

8 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
Ci di cui abbiamo bisogno poter clonare il filehandle originale, facendo in modo da riutilizzare
anche il descrittore: quello che - nel sistema operativo - fa fdopen(). Non sorprende, pertanto,
che fra le 2000 varianti di open() ce ne sia anche una che si comporta come fdopen():
open my $clone, '<&=', \*STDIN
# notare il carattere "="
or die "fdopen/open(): $!";
stampa_descrittore(clone => $clone); # clone ha descrittore 0

Non avevamo detto che open() era la panacea a tutti i nostri problemi di redirezione? Per
aggirare un modulo ``alla buona'', quindi, la sequenza pi corretta sarebbe la seguente:
# Ad inizio programma, quando i filehandle sono ancora "intatti"
open my $STDIN_originale, '<&=', \*STDIN
or die "fdopen/open(): $!";
# ...
# Ad un certo punto il modulo far qualcosa del genere:
*STDIN = $nuovo_input;
# ...
# ...
# Nel programma, allora, proviamo
my $STDIN_nuovo = \*STDIN;
#
*STDIN = $STDIN_originale;
#
open STDIN, '<&', $STDIN_nuovo; #

ad invertire
salva quanto impostato dal modulo
ripristina STDIN, descrittore compreso
redirezione corretta

Ma Ne Abbiamo Bisogno?
Ripristinare la corretta associazione filehandle/descrittore pu essere importante per vari motivi. Se
ci interessa unicamente perch vogliamo chiamare exec() ed essere sicuri di impostare i giusti
flussi standard al programma che stiamo per chiamare, per, probabilmente tutto il lavoro di
salva/ripristina/redirigi correttamente che abbiamo descritto un po' troppo. Quello di cui abbiamo
veramente bisogno, in fondo, poter lavorare sui descrittori standard 0, 1 e 2.
A tal proposito, il modulo POSIX mette a disposizione esattamente la funzione che ci serve, ossia
dup2(). Questa funzione fa un mestiere piuttosto semplice: clona le impostazioni associate ad un
descrittore su un altro descrittore, entrambi di nostra scelta. Nell'esempio pipe()/fork(),
quindi, possiamo cavarcela molto semplicemente:
my ($figlio_r, $figlio_w, $padre_r, $padre_w);
pipe($figlio_r, $padre_w);
pipe($padre_r, $figlio_w);
defined(my $pid = fork()) or die "fork(): $!";
if ($pid) { # padre
close $figlio_r;
close $figlio_w;
Perl Mongers Italia. Tutti i diritti riservati.

9 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
# ... dialoga con il figlio utilizzando:
#
$padre_r per leggere dal figlio
#
$padre_w per scrivere al figlio
}
else {
# figlio
close $padre_r;
close $padre_w;
require POSIX;
POSIX::dup2(fileno($figlio_r), 0);
POSIX::dup2(fileno($figlio_w), 1);

# contiene la funzione dup2


# REDIRIGI stdin su $figlio_r
# REDIRIGI stdout su $figlio_w

exec {$programma} $programma, @ARGOMENTI


or die "exec('$programma'): $!";
}

Tornare Indietro
Ora abbiamo abbastanza materiale per poter rispondere anche ad un'altra domanda: come torno
indietro dopo aver fatto una redirezione? Come abbiamo detto prima, ad esempio, potremmo aver
rediretto l'output di una parte del codice per catturarlo in una variabile, in modo da avere la
possibilit di operare qualche trasformazione (come cancellare le parolacce, o aggiungere numeri
di riga) prima di stampare effettivamente. Se ho rediretto l'output, per... come faccio a stampare
effettivamente?

Capitalizziamo Quanto Imparato


Il sistema pi generale quello di dup()licare l'elemento che ci interessa nella tabella dei file del
processo, per poterlo ripristinare in seguito:
# salva STDOUT per poterlo riutilizzare in seguito
open my $STDOUT_originale, '<&', \*STDOUT or die "dup/open(): $!";
my $testo_catturato;
close STDOUT; # Ricordate? Va chiuso quando si opera con la variabile!
open STDOUT, '>', \$testo_catturato or die "open(): $!";
# ...
print
print
print

ora, la "print" opera su $testo_catturato!


"una riga, scemo!\n";
"altra riga\n";
"ultima riga, scemo!\n";

$testo_catturato =~ s{scemo}{**beep**}gi;
# per stampare, posso usare $STDOUT_originale...
print {$STDOUT_originale} "Testo 'ripulito':\n";
# ... oppure ripristinare STDOUT
Perl Mongers Italia. Tutti i diritti riservati.

10 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
open STDOUT, '<&', $STDOUT_originale or die "dup/open(): $!";
print $testo_catturato;

Una Scorciatoia
Avete mai usato la funzione local in un programma Perl? No? Fate bene, perch nella stragrande
maggioranza dei casi non ne avete bisogno. Per...
Quando localizzate una variabile (rigorosamente di pacchetto, non potete farlo con una variabile
my), sostanzialmente state creando una copia temporanea che ``dura'' finch non viene chiuso il
blocco in cui appare questa localizzazione. Ad esempio, se volete leggere un file tutto d'un fiato,
potete impostare $/ ad undef giusto il tempo di effettuare la lettura:
my $contenuto_file = do { # apre un blocco
local $/;
# automaticamente impostata a "undef"
open my $fh, '<', $nomefile or die "open('$nomefile'): $!";
<$fh>;
}; # fine del blocco, $/ viene ripristinata al valore precedente

Visto che i filehandle STDIN, STDOUT e STDERR sono agganciati al GLOB omonimo nel pacchetto
main, un sistema molto rapido per rendere temporanea una redirezione consiste proprio nel
localizzare il GLOB stesso:
my $testo_catturato;
{
local *STDOUT;
open STDOUT, '>', \$testo_catturato or die "open(): $!";
# ...
print
print
print

ora, la "print" opera su $cattura!


"una riga, scemo!\n";
"altra riga\n";
"ultima riga, scemo!\n";

}
$testo_catturato =~ s{scemo}{**beep**}gi;
# Qui STDOUT ritorna quello originale!
print "Testo 'ripulito':\n";
print $testo_catturato;

Viene stampato:
Testo 'ripulito':
una riga, **beep**
altra riga
ultima riga, **beep**

Perl Mongers Italia. Tutti i diritti riservati.

11 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
Da notare che, in questo caso, non abbiamo avuto bisogno di chiudere il filehandle STDOUT.
Perch? Semplice: a valle dell'operazione di localizzazione, il filehandle STDOUT non ``punta'' pi
all'originale - che dovremmo chiudere - ma indefinito, per cui non c' proprio niente da chiudere.
Questo sistema pu essere utilizzato come tecnica di difesa contro i moduli che effettuano la
redirezione alla buona. Ritornando all'esempio sviluppato in precedenza, una possibile soluzione
alternativa la seguente:
# ...
# Ad un certo punto dovremo chiamare il modulo...
my $STDIN_nuovo;
{
local *STDIN; # Inganno! Ora possiamo chiamare il modulo...
# ... che far qualcosa tipo:
*STDIN = $nuovo_input;
# Prima di uscire da questo blocco:
open $STDIN_nuovo, '<&', \*STDIN; # or die... omesso
}
# Nel programma, allora, proviamo ad invertire
open STDIN, '<&', $STDIN_nuovo; # redirezione corretta

Insomma, local non proprio una funzione con cui giocare troppo - in generale non ne avrete
mai bisogno, per le variabili utilizzate my - ma ha ancora una nicchia di utilit.

Concludendo...
... possiamo dire che redirigere i flussi standard di un programma non particolarmente
complicato, anche se dobbiamo fare attenzione a farlo nella maniera giusta per non avere sorprese
e perdere troppo tempo a capire cosa succede.
Come approfondimento, sicuramente consiglierei di dare un'occhiata al manuale Perl su
perlfunc/open. Se poi vi rimasto il dubbio su cosa siano questi famigerati GLOB, probabilmente
un'occhiata a perldata sarebbe d'uopo.
Se proprio siete curiosi di sapere quando non vi rideranno dietro se usate local, potete leggere
l'articolo di Mark Jason Dominus Coping with Scoping (in inglese), anche disponibile in italiano
nell'ottima traduzione di larsen Lo Scopo Dello Scope. Ok, viene detto che non dovete mai usare
local, ma non proprio vero... date un'occhiata all'articolo (sempre di Mark Jason Dominus),
all'indirizzo Seven Useful Uses for local (in inglese).
Non mi vengono invece in mente moduli che potrebbero esservi utili su questo argomento...
Perl Mongers Italia. Tutti i diritti riservati.

12 of 13

Flavio Poletti

Redirezione
http://www.perl.it/documenti/articoli/2008/06/redirezione.html
suggerimenti?
Perl Mongers Italia. Tutti i diritti riservati.

13 of 13

Potrebbero piacerti anche