¿Por qué no fuera Perl archivo glob () obra de un bucle en el contexto escalar?

StackOverflow https://stackoverflow.com/questions/2633447

  •  26-09-2019
  •  | 
  •  

Pregunta

De acuerdo con la documentación de Perl en el archivo de englobamiento, la función <*> operador o glob (), cuando se utiliza en un contexto escalar, debe recorrer la lista de archivos que coincidan con el patrón especificado, devolviendo el siguiente nombre de archivo cada vez que se llama o undef cuando no hay más archivos.

Sin embargo, el proceso de iteración sólo parece trabajar desde dentro de un bucle. Si no es en un bucle, entonces parece que empezar de nuevo inmediatamente antes de que se hayan leído todos los valores.

A partir de la documentación de Perl:

En contexto escalar, itera glob a través de tales expansiones nombre de archivo, que regresan undef cuando la lista se ha agotado.

http://perldoc.perl.org/functions/glob.html

Sin embargo, en el contexto escalar el operador devuelve el siguiente valor cada vez que se llama, o undef cuando la lista se ha agotado.

http://perldoc.perl.org/perlop.html#I/O-Operators

Ejemplo código:

use warnings;
use strict;

my $filename;

# in scalar context, <*> should return the next file name
# each time it is called or undef when the list has run out

$filename = <*>;
print "$filename\n";
$filename = <*>;      # doesn't work as documented, starts over and
print "$filename\n";  # always returns the same file name
$filename = <*>;
print "$filename\n";

print "\n";

print "$filename\n" while $filename = <*>; # works in a loop, returns next file
                                           # each time it is called

En un directorio con 3 archivos ... file1.txt, file2.txt y file3.txt, la salida del código de voluntad por encima de:

file1.txt
file1.txt
file1.txt

file1.txt
file2.txt
file3.txt

Nota: El script Perl real debe estar fuera del directorio de prueba, o verá el nombre de archivo del script en la salida también.

¿Estoy haciendo algo mal aquí, o se trata de la forma en que se supone que funciona?

¿Fue útil?

Solución

Esta es una manera de capturar la magia de estado del operador <> pegote en un objeto que se puede manipular en una especie normal de forma: submarinos anónimos (y / o cierres)

sub all_files {
    return sub { scalar <*> };
}

my $iter = all_files();
print $iter->(), "\n";
print $iter->(), "\n";
print $iter->(), "\n";

o tal vez:

sub dir_iterator {
    my $dir = shift;
    return sub { scalar glob("$dir/*") };
}
my $iter = dir_iterator("/etc");
print $iter->(), "\n";
print $iter->(), "\n";
print $iter->(), "\n";

A continuación, una vez más mi inclinación es presentar esto bajo "curiosidad". No haga caso de esta rareza particular de glob() / <> y el uso opendir / readdir, IO :: Todos / readdir, o archivo :: Glob lugar:)

Otros consejos

El siguiente código también parece crear 2 instancias independientes del iterador ...

for ( 1..3 )
{
   $filename = <*>;
   print "$filename\n" if defined $filename;
   $filename = <*>;
   print "$filename\n" if defined $filename;
}

supongo que veo la lógica allí, pero es una especie de contra intuitivo y contradictorio a la documentación. Los documentos no mencionan nada acerca de tener que estar en un bucle para la iteración de trabajo.

También desde perlop :

  

A (archivo) pegote evalúa su argumento (incrustado) sólo cuando se está iniciando una nueva lista.

Llamando glob crea una lista, ya sea que se volvió todo (en el contexto de lista) o se recupera un elemento a la vez (en el contexto escalar). Pero cada llamada a glob crea una lista independiente.

(escarbando en mi memoria oxidada de Perl ...) Creo que varias instancias léxicas de <*> son tratados como invokations independientes de pegote, mientras que en el bucle while que está invocando el mismo "ejemplo" (lo que significa) .

Imagínese, por ejemplo, si se hizo esto:

while (<*>) { ... }
...
while (<*>) { ... }

Por supuesto que no sería esperar que esos dos invocaciones a interfieren entre sí.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top