Why does Perl glob return undef for every other call?

I'm not necessarily looking for the best way to do this, and the explanations for the output will be much appreciated. Recently, a senior programmer asked me why his code worked, but only for one instance. What I found out was that it worked on every other occasion. Here is my example:

#!/usr/bin/perl -w use strict; my @list_env_vars = ( '$SERVER', '$SERVER', '$SERVER', '$SERVER', '$SERVER', '$SERVER', ); foreach (@list_env_vars){ print "$_ = ".glob()."\n"; } 

which are displayed for perl 5.004:

 $SERVER = UNIX_SERVER $SERVER = $SERVER = UNIX_SERVER $SERVER = $SERVER = UNIX_SERVER $SERVER = 

or output for perl 5.10:

 $SITE = $SITE Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14. $SITE = $SITE = $SITE Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14. $SITE = $SITE = $SITE Use of uninitialized value in concatenation (.) or string at glob_test.pl line 14. $SITE = 

I personally have never used glob () this way, so I was poorly prepared to answer it. I read the perldoc glob documentation and followed File :: Glob on this page and still cannot find anything that could explain the output. Any help would be greatly appreciated.

+4
source share
3 answers

glob in scalar context:

In a scalar context, glob iterates through such file name extensions, returning undef when the list is exhausted.

IN

 foreach (@list_env_vars){ print "$_ = ".glob()."\n"; } 

glob() really is glob($_) . Each iteration of $_ contains the string $SERVER . Given that the environment variable does not change, $SERVER expands to the same line. This string is returned for the first time. Then the list is exhausted, so undef returned. The third time we start ....

Explanation: It does not matter that the argument of the second call is the same as for the first call, since there is no way to reset the glob iterator.

This can be done more clearly using the following example (the current directory contains files 1.a ', 1.b', '2.a' and '2.b'):

 #!/usr/bin/perl -w use strict; my @patterns = ( '*.a', '*.b', ); for my $v ( @patterns ) { print "$v = ", scalar glob($v), "\n"; } 

Output:

  C: \ Temp> d
 * .a = 1.a
 * .b = 2.a

I would recommend accessing the environment variables through the %ENV hash:

 my @list_env_vars = ($ENV{SERVER}) x 6; 

or

 my @list_env_vars = @ENV{qw(HOME TEMP SERVER)}; 
+13
source

By the way, the reason is that at 5.004 you get a variable extension, and at 5.10 you just return your literal string, because on the old perl, glob() executed by the system shell, which, the effect performs a variable extension. Since perl 5.6, glob() uses the File::Glob module, which does the work itself, without a shell, and does not extend environment variables (which they never intended to do). %ENV is the right way to access your environment.

+4
source

Notes on old behavior, wiki'd for your convenience (and therefore I have a full range of markup and no more than 500 - char):

The fact that glob and <*globbything*> changed to 5.6 is mentioned in the transmission in documents ( perl56delta , perlop , -f glob ), but the only real source of exactly how it worked is the pre-5.6 version of perlop . Here is the corresponding bit from 5.005:

Example:

 while (<*.c>) { chmod 0644, $_; } 

equivalently

 open(FOO, "echo *.c | tr -s ' \t\r\f' '\\012\\012\\012\\012'|"); while (<FOO>) { chop; chmod 0644, $_; } 

In fact, it is currently implemented that way. (This means that it will not work with file names with spaces in them unless you have csh (1) on your computer.)

Hehe, these are pretty evil things. Anyway, if you ever want to consult old perldocs like this, just go to search.cpan.org, pull the perl distribution, use the drop-down list to select the old version, then click on the document so you need to. perl itself is not “cleaned up” from CPAN; Currently, everything from 5.004 is available without clicking BackPan.

0
source

All Articles