in reply to Fileglob in scalar context question

To continue the explaination by Japhy, I think you're confused that the return value is the same as the stuff between the angles. It's returning the file name, and since there are no wildcards, what else can it find?! It's not returning a fully-quallified name with path information added, if that's what you mean. You're essentially doing an "exists" test on that one file -- it will return that name back if it exists, undef otherwise, and meanwhile keep a persistant state.

I don't know what to make of the persistant state. If you change the current working directory, how does one reset the state? If it contains a variable, and the variable changes, how do you know when to continue or start over?

—John

  • Comment on Re: Fileglob in scalar context question

Replies are listed 'Best First'.
Re: Re: Fileglob in scalar context question
by tye (Sage) on Jun 30, 2001 at 00:49 UTC

    Actually, it returns "test.txt" even if the file doesn't exist.

            - tye (but my friends call me "Tye")
      Why would it do that?

        Because it makes sense. q-:

        But seriously, although it makes some sense to have glob on a non-wildcard string turn into a substitute -e operator, there are quite a few reasons why the current behavior is convenient.

        For example, if it didn't, you couldn't just write: @ARGV= map glob, @list; you'd have to write something like: @ARGV= map { my @g= glob; @g ? @g : $_ } @list; in order to process a list of file specs where you wanted to support wildcards.

        You couldn't abuse glob for generating lists of related strings: @mispel= glob( "g{u,a,au,ua}r{r,}{a,u,e}nt{i,e,}{e,y}" );

        You'd have to do double error reporting:

        print "File(s): "; chomp( my $fileSpec= <STDIN> or exit(0) ); my @files= glob($fileSpec) # vvv or warn "No files matching $fileSpec found.\n"; # ^^^ This line not needed with current glob(). foreach my $file ( @files ) { if( ! open( FILE, "<$file" ) ) { warn "Can't read file, $file: $!\n"; next; } #...

        Worse still, since the default glob allows multiple file specs separated by spaces, the above would really have to be:

        print "File(s): "; my $fileSpec= <STDIN> or exit(0); my @files= map { glob($fileSpec) or (warn "No files matching $fileSpec found.\n")[()]; } split ' ', $fileSpec; foreach my $file ( @files ) { #...
        in order to prevent "*.pl Makefile *.c" from just silently ignoring "Makefile" if that file didn't exist.

        Though, on that last item, it is interesting to note that for the case of wildcards that don't match anything the behavior of csh's "glob" command were overridden by Perl such that an empty list is returned instead of the unexpanded original wildcard. This means that the above would silently ignore "*.pl" if there is nothing to match it. But then I think some people didn't like the way shell scripts end up trying to open a file named "*.pl" and complaining "can't open" instead of "no match".

        It is a bit of a mixed blessing, but I think the advantages outweigh the disadvantages. Especial since the simple: grep -e, glob gives you the other behavior (though a bit less efficiently).

        Then there is also the implementation-motivated explanation where the writer of glob has to find the wildcard characters then list all of the files and return only the ones that match. However, when you find there are no wildcard characters, why would you go through the work of listing all of the files to see if one matched exactly? So the "no wildcard" case ends up being a special case in the code. The whole rest of the code for glob never calls stat, so it feels a bit strange throwing in a call to stat for that one case.

        Of course, it would be neat on case-ignoring file systems if glob("makefile") returned "Makefile" if that was the actual case of the matching file name. But that isn't currently the case. (:

        Update: Yes, it is inconsistant.

                - tye (but my friends call me "Tye")
Re: Re: Fileglob in scalar context question
by scain (Curate) on Jun 30, 2001 at 01:04 UTC
    John,

    While you are probably right about being confused about "the stuff between the angles", the original program did have a wild card in it. In the first pass through the loop, it would look like </home/scott/manydirs/0/*test.txt>.

    However, on thinking about this problem more, I think I would rewrite the code to look like this:

    #!/usr/bin/perl -w use strict; my @EXON_IN = </home/scott/manydirs/[0-9]*/*test.txt>; foreach my $file (@EXON_IN){ #do whatever it was my coworker wanted to do #Greg, are you looking? }
    Which is probably what I would have done if I was doing this from scratch, but when presented with another's code, it is often hard to think of the "right" thing to do right away.

    Thanks,
    Scott