http://www.perlmonks.org?node_id=1042924

walkingthecow has asked for the wisdom of the Perl Monks concerning the following question:

I have directories on my Solaris 10 box like so:
/home/vize/units/11780540/moving_code_AFT /home/vize/units/91540670/moving_code_INT ..etc
Now, each one of those numbers I am referring to as a unit. The moving_code_(THREE CAPITAL LETTERS) directory has three random letters, so I am using glob to figure out what the directory is named. However, I am running into an issue.
#!/usr/bin/perl use strict; use warnings; my $UNIT_DIR = '/home/vize/units'; # Get all units in $UNIT_DIR my $dh; opendir $dh, $UNIT_DIR or die "Couldn't open dir '$UNIT_DIR': $!"; my @units = grep { !/^\.\.?$/ } readdir $dh; closedir $dh; if ( @units ) { foreach my $unit (@units) { my $moving_code_dir = glob("$UNIT_DIR/$unit/moving_code_*"); my $moving_code = (split("/",$moving_code_dir))[-1]; if ( $moving_code_dir ) { print "$unit good\n"; } else { print "$unit bad\n"; } } }
Simple, not much really there. The problem I am having is that this piece of code always finds the moving_code_ directory for every other unit, even though the directory exists for every unit.
00116122 good 00114295 bad 00114952 good 00116121 bad 00117351 good 00114294 bad 00114293 good 00114292 bad 00114291 good 00117349 bad 00116120 good 00116119 bad
Now, I know the moving_code_ directory is there, and it's the same as the previous unit (except the three random letters), so I'm not sure why it's not finding it. Could this be an issue with Solaris 10 filesystem? Am I doing something wrong with my glob here? Any ideas? I am at a loss.

Replies are listed 'Best First'.
Re: Coming across an issue with glob. Is only able to find every other directory.
by Athanasius (Archbishop) on Jul 06, 2013 at 16:54 UTC

    The problem is that you’re calling glob in scalar context, but expecting it to behave as if called in list context. See I/O Operators:

    A (file)glob evaluates its (embedded) argument only when it is starting a new list. All values must be read before it will start over. In list context, this isn't important because you automatically get them all anyway. However, in scalar context the operator returns the next value each time it's called, or undef when the list has run out. ... So if you're expecting a single value from a glob, it is much better to say

    ($file) = <blurch*>;

    than

    $file = <blurch*>;

    because the latter will alternate between returning a filename and returning false.

    Update: I don’t have a Solaris box, but on Windows I created two directories: ...\666_SoPW\home\vize\units\11780540\moving_code_AFT and ...\666_SoPW\home\vize\units\91540670\moving_code_INT and ran the OP code, with the following result:

    12:25 >perl 666_SoPW.pl 11780540 good Use of uninitialized value $moving_code_dir in split at 666_SoPW.pl li +ne 41. 91540670 bad 12:25 >

    I then changed the line:

    my $moving_code_dir = glob("$UNIT_DIR/$unit/moving_code_*");

    to

    my ($moving_code_dir) = glob("$UNIT_DIR/$unit/moving_code_*");

    as per the documentation quoted above, and the output is:

    12:25 >perl 666_SoPW.pl 11780540 good 91540670 good 12:26 >

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Re: Coming across an issue with glob. Is only able to find every other directory.
by Perlbotics (Archbishop) on Jul 06, 2013 at 17:11 UTC

    Your program works fine under Linux (OpenSUSE 12.3) and Perl 5.14.1 if you ignore the undefined warnings.
    Hint: do this in the good-branch: my $moving_code = (split("/",$moving_code_dir))[-1];).

    It could be a Solaris issue. Which Perl version do you use?

    From File::Glob:

    Since v5.6.0, Perl's CORE::glob() is implemented in terms of bsd_glob(). Note that they don't share the same prototype--CORE::glob() only accepts a single argument. Due to historical reasons, CORE::glob() will also split its argument on whitespace, treating it as multiple patterns, whereas bsd_glob() considers them as one pattern.
    From perlport:
    Don't count on filename globbing. Use "opendir", "readdir", and "closedir" instead.
    HTH

Re: Coming across an issue with glob. Is only able to find every other directory.
by jwkrahn (Abbot) on Jul 07, 2013 at 06:05 UTC

    You should use glob like this:

    my $UNIT_DIR = '/home/vize/units'; # Get all units in $UNIT_DIR foreach my $moving_code_dir ( <$UNIT_DIR/*/moving_code_*> ) { my $moving_code = ( split '/', $moving_code_dir )[ -1 ]; if ( $moving_code_dir ) { print "$unit good\n"; } else { print "$unit bad\n"; } }