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

Hi all,

I have a simple script:

#!/usr/bin/perl -w
use strict;
use warnings;

opendir (DIR, "/some/path");
my @array = readdir(DIR);
closedir (DIR);

my $size = @array;
print "number of files: " . $size-2 . "\n";


it will return:
Argument "size - 2: 4" isn't numeric in subtraction (-) at test.pl line 11. -2


Could someone explain? I thought PERL does not care if the variable is a string or numeric.
Assuming that there are only files in the directory (directory does not contain sub-directory), and since there are two files in that directory, I was expecting the result to print "number of files: 2" (the two files, minus the . and .. values).

TIA
Theiss

Replies are listed 'Best First'.
Re: why scalar(@array) is not numeric?
by Fletch (Bishop) on Jul 16, 2009 at 23:10 UTC

    You have a precedence problem. Quoth B::Deparse your code parses as: print(((('number of files: ' . $size) - 2) . "\n"));. print takes a list so you should use a comma rather than the concatenation operator ..

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      thank you thank you thank you.
      I spent a better half of today trying to figure it out.
      I guess I'll read up on the . vs , :)
      Thanks Again!

      Theiss
Re: why scalar(@array) is not numeric?
by aufflick (Deacon) on Jul 17, 2009 at 00:37 UTC
    As id:Fletch says, using comma to provide a list to print elegantly solves the problem.

    To make it clearer that it is purely a precedence issue though, you can fix your existing statement by making precedence explicit with brackets:

    print "number of files: " . ($size-2) . "\n";

      Also check out perlop for the precedence table. . and - bind at the same level. , is lower on the table, so the minus would get executed first.

      --MidLifeXis

      The tomes, scrolls etc are dusty because they reside in a dusty old house, not because they're unused. --hangon in this post

Re: why scalar(@array) is not numeric?
by ikegami (Patriarch) on Jul 17, 2009 at 16:26 UTC
    • Note that the error indicated

      "number of files: 4" isn't numeric

      rather than

      "4" isn't numeric

    • Subtracting 2 is not the way to go. Some directories on some file systems don't have "." and "..". It's better to just filter them out.

      # Filter out "." and ".." my @array = grep !/^\.\.?\z/, readdir(DIR);
      # Filter out all "hidden" files my @array = grep !/^\./, readdir(DIR);
    • There's no reason to use a global variable for your directory handle. Change

      opendir (DIR, "/some/path"); my @array = grep !/^\.\.\z/, readdir(DIR); closedir (DIR);

      to

      opendir (my $dh, "/some/path"); my @array = grep !/^\.\.\z/, readdir($dh); closedir ($dh);
    • Finally, you should have some error checking, if only something minimalistic for opendir

      opendir (my $dh, "/some/path") or die("opendir: $!\n");
      I've always been partial to:
      use File::Slurp; my @files = read_dir( '/path/to/dir' ) ;