Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl: the Markov chain saw

forcing list-context

by morgon (Curate)
on Jan 23, 2012 at 14:32 UTC ( #949420=perlquestion: print w/replies, xml ) Need Help??
morgon has asked for the wisdom of the Perl Monks concerning the following question:


I need to find the number of entries in a directory, so I do this:

opendir my $dh, $dir or die $!; my $entries = grep {1} readdir $dh;
What bugs me is the "grep {1}"-thing that I do for the sole purpose of forcing a list-context on the readdir as doing simpy a $entries = scalar (readdir $dh) (i.e. putting paentheses around the call) does not do the trick...

So I wonder now: What is the idiomatic way to force list-context?

Many thanks!

Replies are listed 'Best First'.
Re: forcing list-context
by choroba (Bishop) on Jan 23, 2012 at 14:40 UTC
    Assign to an emtpy list:
    my $entries =()= readdir $dh;
      ... minus 2, unless you want to sum . and ..
      AKA the "goatse operator" -- google it!
        goatse ... google it!


Re: forcing list-context
by BrowserUk (Pope) on Jan 23, 2012 at 20:22 UTC

    Unfortunately, even the squeeze operator will still build a long list then discard it, in order to count its members.

    More efficient would be:

    my $entries = -2; ++$entries while readdir $dh;

    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    The start of some sanity?

Re: forcing list-context
by JavaFan (Canon) on Jan 23, 2012 at 14:55 UTC
    Well, scalar enforces scalar context, not list context. It's the LHS of the assignment that determines context. Putting the readdir in list context is easy:
    my ($entries) = readdir $dh;
    Note that this not solve your problem. Because you phrased it as an XY problem. You want to solve X, you think Y solves X, so you ask how to solve Y. But Y (putting readdir in list context) does not solve X (finding out the number of entries in a directory). At least, not directly. You can assign the result of readdir to a list and put that assignment in scalar context; this will give you the number of entries in the directory. One way of doing this is:
    my $entries = () = readdir $dh;
    The parens here indicate an (empty) list.
      Well, scalar enforces scalar context, not list context.
      I know that.

      I did not try to enforce list-context with "scalar" but by putting the expression I wanted to evaluate in list-context in parentheses.

Re: forcing list-context
by ikegami (Pope) on Jan 23, 2012 at 22:25 UTC

    There are two assignment operator.

    • The scalar assignment operator imposes scalar context on both of its operands.
    • The list assignment operator imposes list context on both of its operands.

    The choice of which assignment operator is used is based on what syntax of its LHS operand. If it "looks like a list", the list assignment operator will be used.

    (my $first_entry) = grep ...; my ($first_entry) = grep ...; my @entries = grep ...;

    Related: Mini-Tutorial: Scalar vs List Assignment Operator.

Re: forcing list-context
by Arunbear (Prior) on Jan 23, 2012 at 17:31 UTC
    Another way is to unload the readdir call into a temporary array and then call scalar on that e.g.
    say scalar(@{[readdir $dh]});
    Though this is not as economical (memory wise) as the above solution in Re: forcing list-context
Re: forcing list-context
by pvaldes (Chaplain) on Jan 23, 2012 at 15:22 UTC
    I need to find the number of entries in a directory.
    my $dir = '/home/itsme/some/dir'; chdir $dir; my $filenum = 0; my $dirnum = 0; my $linknum = 0; opendir my $dh, $dir or die $!; foreach(readdir $dh) { if (-f){$filenum++} elsif (-l){$linknum++} elsif (-d){$dirnum++} } print "You have $filenum files, $linknum links and $dirnum directories + in $dir\n"; closedir $dh;

    *(please note that this count is not recursive)

    Updated: chdir line added (random results if this line is not activated)

      foreach(readdir $dh) { if (-f){$filenum++} elsif (-l){$linknum++} elsif (-d){$dirnum++} }

      You are not going to get an accurate total because you are counting soft links in both $filenum and $linknum.    That would be better as:

      foreach ( readdir $dh ) { lstat; if ( -f _ ) { $filenum++ } elsif ( -l _ ) { $linknum++ } elsif ( -d _ ) { $dirnum++ } }

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://949420]
Approved by Corion
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others studying the Monastery: (4)
As of 2018-03-18 05:10 GMT
Find Nodes?
    Voting Booth?
    When I think of a mole I think of:

    Results (228 votes). Check out past polls.