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

I'm writing my first ever script to delete non numeric files from various directories and I'm not too sure which way I should get the file names.
I have got a foreach loop working but it doesn't list the . files. My opendir does list the files though.
My O'Reilly Learning Perl doesn't have an explanation that I can find.
Is my opendir use better or more efficient etc that the foreach command?
Do I have to do multiple foreach's and include a (</xxx/*>) or (</xxx/.*>)>.
I have included my test script as well (it even works!).
#!/usr/bin/perl -w use strict; use diagnostics; my @dirvar=""; my $foreachvar=""; opendir(DIRHAN,"/xxx"); @dirvar = readdir(DIRHAN); print "@dirvar\n"; closedir(DIRHAN); foreach $foreachvar (</xxx/*>) { if (-f $foreachvar) {print "$foreachvar \n" } }

Many Thanks,
Dobby
P.S. sory about the format, I'm trying to get to grips with this <code><br> stuff. Its HTML isn't it?

Replies are listed 'Best First'.
Re: foreach and opendir differences
by Tanktalus (Canon) on Apr 07, 2005 at 03:49 UTC

    It's not actually a foreach problem.

    my @dirvar = </xxx/*> print join ':', @dirvar;
    It's a glob problem. Which reminds me - I recommend avoiding the <...> operator for that. Not just because it's a pain to type and get to display properly here ;-), but because using "glob" is so much more obvious as to what you're doing. (<...> is implemented in terms of glob, so this doesn't change anything functionally)
    my @dirvar = glob "/xxx/*";
    Looking up glob in the perlfunc documentation (e.g., "perldoc -f glob"), you see it is implemented via File::Glob. Looking that up, you see it tries to implement C shell semantics. This sets off warning bells: on unix, files with a leading dot are considered "hidden" and should not be shown by default. So "*" does not match leading dots. Other dots, but not leading dots. Looking C shell up (I'm a Korn shell/Bourne-again shell type of guy m'self), I see that this should work:
    my @dirvar = glob "/xxx/{.,}*";
    The reason? Braces denote choices, all of which apply. The comma separates the choices. So this expands to both "/xxx/.*" and "/xxx/*" simultaneously, in a single call.

    readdir, by the way, does not use shell semantics, and thus ignores "hidden" attributes, laying everything out for you.

    HTH

Re: foreach and opendir differences
by jpeg (Chaplain) on Apr 07, 2005 at 04:09 UTC
    It's the difference between shell expansion using * and ..., well, readdir.

    perldoc perlop, perldoc -f glob, and perldoc File::Glob
    has a lot of info about <> and its many behaviors. As you're using it with foreach, you're globing in list context, using glob behavior as per a /bin/csh. I poked through man csh a bit, but can't find a documented reason why an asterisk would ignore dotfiles. When I'm in csh and bash, a ls /dir/* also ignores dotfiles, so I guess it's working as expected.

    readdir, on the other hand, probably uses the readdir system call, documented in man 3 readdir. It actually reads the directory as a file, which is a list of inodes and always contains . and .. as entries.

    As far as the code tags... no idea. there's probably some page with instructions for writeups we should have read somewhere. I just lurked for a bit and copied people ;)

Re: foreach and opendir differences
by dobby (Initiate) on Apr 07, 2005 at 04:25 UTC
    Is there a preference or a best practice or doesn't it matter. I know I can do it as a one liner from a system call but I want to learn bad habits.
    Dobby.

      ...but I want to learn bad habits
      Wow, so many to choose from. Smoking, not using strict, leapfrogging unicorns (bad, but not always practical - substitute rhinos if unicorns are unavailable) not wearing pants to work...
      I think bad habits are called that for a reason, but hey, do what you need to do.