Newsgroup: it.comp.lang.perl
Titolo: Ricorsione for dummies

Salve a tutti,
ho cominciato a studiare il Perl qualche giorno fa e come esercizio volevo
leggere tutti i file di una directory e delle sue sottodirectory,
ricorsivamente (poi usero' File::Find, ma ora volevo farlo per capire il
meccanismo). Bazzicando un po' il Perl Cookbook ho scritto questo codice, ma
non funziona:
$dir = "...";
ricerca($dir);
sub ricerca{
 my $percorso=$_[0];
 opendir(BIN, $percorso) or die "Can't open $percorso: $!";
 while(defined($file=readdir BIN)){
  next if $file =~ /^\./;   #filter out dot files
  if(-f "$percorso/$file"){
   print "Letto file: $file\n";
  } elsif(-d "$percorso/$file") {
   print "Letta directory: $file\n";
   ricerca("$percorso/$file");}
 }
 closedir(BIN);
}
Quello che succede e' che parte dalla directory, scende lungo tutte le prime
sottodirectory che incontra, arrivato all'ultimo livello scrive l'elenco dei
file di questo ultimo livello... e basta. Non ritorna al livello precedente
per ripetere la scansione.
Mi date qualche dritta? Grazie,
Pleg

per ripetere la scansione.
Non ho analizzato in dettaglio il ciclo, ma credo che il problema sia
nell'handle della directory BIN. A differenza delle variabili definite con
my, infatti, non č locale; viene, sě, riaperto ad ogni opendir, ma l'handle
č sempre il medesimo, quindi, al termine di una ricorsione, non ricomincia
da dove si era interrotto.
Prova ad usare una variabile my, ma comunque leggi anche la documentazione
a riguardo dei filehandle.
Ciao.

 l'elenco dei file di questo ultimo livello... e basta.
I file/dir handler con nome (es. BIN) sono globali, perciň la varie chiamate
a 'opendir' azzerano lo stato corrente di 'BIN'.
Soluzioni: salva l'elenco file in un array prima di invocare ricorsivamente
'ricerca', oppure usa IO::Dir invece di 'opendir'.
Max

'ricerca', oppure usa IO::Dir invece di 'opendir'.
C'č un trucco simpatico, segnalato nella documentazione della funzione
open:
    foreach $file (@ARGV) {
        process($file, 'fh00');
    }
    sub process {
        my($filename, $input) = @_;
        $input++;           # this is a string increment
        unless (open($input, $filename)) {
            print STDERR "Can't open $filename: $!\n";
            return;
        }
        local $_;
        while (<$input>) {  # note use of indirection
            if (/^#include "(.*)"/) {
                process($1, $input);
                next;
            }
            #...            # whatever
        }
    }
qui č utilizzato per processare ricorsivamente una serie di file, e i file
da questi inclusi con "#include", ma funziona naturalmente anche per il
caso in esame, con opendir.
Quello che non mi č del tutto chiaro č la differenza rispetto a:
    ...
    opendir my $BIN, $percorso;
    ...
che pure mi sembra che funzioni, in perl 5.8 ("If FILEHANDLE is an
undefined scalar variable (or array or hash element) the variable is
assigned a reference to a new anonymous filehandle", cosě anche in
perlopentut: "Indirect Filehandles - open's first argument can be a
reference to a filehandle. As of perl 5.6.0, if the argument is
uninitialized, Perl will automatically create a filehandle and put a
reference to it in the first argument").
Ciao.

Grazie a tutti!
Pleg

 
Non mi è chiaro che cosa non ti sia chiaro, quindi forse chiarirò qualcosa
che ti è già chiaro.
Nel primo caso i vari valori di $input ('fh00', 'fh01', etc.) vengono usati
come riferimenti simbolici. Il codice non può funzionare sotto "strict
refs".
Nel secondo caso, a $BIN viene assegnato un riferimento (non simbolico) a un
filehandle anonimo.
Il vantaggio del secondo (oltre a funzionare con "use strict") è che quando
$BIN esce di scope il corrispondente filehandle viene chiuso.
Max

$BIN esce di scope il corrispondente filehandle viene chiuso.
Ma allora, ed è questo che non mi è chiaro, se è legittimo usare a questo
scopo una variabile lessicale, e se questo risolve il problema, che cosa ci
stanno a fare IO:Handle, IO::Dir e compagnia?
Cioè, ha ancora senso, a questo punto, preoccuparsi delle particolarità
degli handle, rispetto alle variabili? c'è qualche effetto collaterale che
non abbiamo considerato?
Ciao.