Why doesn't Perl file glob() work outside of a loop in scalar context?

后端 未结 4 1083
被撕碎了的回忆
被撕碎了的回忆 2021-02-14 15:49

According to the Perl documentation on file globbing, the <*> operator or glob() function, when used in a scalar context, should iterate through the list of files matching

相关标签:
4条回答
  • 2021-02-14 15:53

    The following code also seems to create 2 separate instances of the iterator...

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

    I guess I see the logic there, but it is kind of counter intuitive and contradictory to the documentation. The docs don't mention anything about having to be in a loop for the iteration to work.

    0 讨论(0)
  • 2021-02-14 15:54

    (Scratching away at my rusty memory of Perl...) I think that multiple lexical instances of <*> are treated as independent invokations of glob, whereas in the while loop you are invoking the same "instance" (whatever that means).

    Imagine, for instance, if you did this:

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

    You certainly wouldn't expect those two invocations to interfere with each other.

    0 讨论(0)
  • 2021-02-14 16:15

    Also from perlop:

    A (file)glob evaluates its (embedded) argument only when it is starting a new list.

    Calling glob creates a list, which is either returned whole (in list context) or retrieved one element at a time (in scalar context). But each call to glob creates a separate list.

    0 讨论(0)
  • 2021-02-14 16:16

    Here's a way to capture the magic of the <> glob operator's state into an object that you can manipulate in a normal sort of way: anonymous subs (and/or closures)!

    sub all_files {
        return sub { scalar <*> };
    }
    
    my $iter = all_files();
    print $iter->(), "\n";
    print $iter->(), "\n";
    print $iter->(), "\n";
    

    or perhaps:

    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";
    

    Then again my inclination is to file this under "curiosity". Ignore this particular oddity of glob() / <> and use opendir/readdir, IO::All/readdir, or File::Glob instead :)

    0 讨论(0)
提交回复
热议问题