http://qs321.pair.com?node_id=171594

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

Simple (probably) but I have gone round and round over the last thirtysix hours looking for this in the docs...

I want @list to contain a list of all directories in "." excluding "." and ".."?

Even better would be an expression that renders an anonymous list?

Thanks.

Replies are listed 'Best First'.
Re: Create a list of directories without . and ..
by dws (Chancellor) on Jun 04, 2002 at 18:34 UTC
    I want @list to contain a list of all directories in "." excluding "." and ".."?

    Try this:

    opendir(DIR, ".") or die ".: $!"; my @list = grep { -d $_ and ! /^\.\.?/ } readdir(DIR); closedir(DIR);
    The anonymous list part is left as an exercise.

        Watch it. That falsely excludes ..foo and .bar. Oops! Maybe you want ...

        Ewps. Typo on my part. I meant

        -d $_ and ! /^\.\.?$/ ^
        though \z would be safer than $.

        Sometimes a regex is overkill.

        !/^\.\.?\z/.

        Less readable, but faster and shorter.

        - Yes, I reinvent wheels.
        - Spam: Visit eurotraQ.
        

      Great suggestion (I ++ed it already). One little flaw that catches me all the time: it breaks as soon as you do apply it to any directory but "./"

      Easy to fix, though. Just be explicit about what directory you're opening.

      my $dir = "."; opendir(DIR, $dir) or die "$dir: $!"; my @list = grep { -d "$dir/$_" and ! /^\./ } readdir(DIR); closedir(DIR);

      "All you need is ignorance and confidence; then success is sure."-- Mark Twain
Re: Create a list of directories without . and ..
by BrowserUk (Patriarch) on Jun 04, 2002 at 18:52 UTC

    Being unsure of the etiquette here, I am not sure if "thankyou"s are in order (but no doubt someone will tell me...:)

    So, until that piece of enlightenment comes my way... Thankyou!!

    Living in darkness; seeking the light; Weak, but will be strong with the help of the Brothers

      you can also use File::Find (as i've recently found)

      something like: (i've not tested this!)

      my @found; File::Find::find({wanted => \&wanted], '.'); sub wanted { if (-d $_) && ($_ != '.') && ($_ != '..') { push(@found, $_) } }
      sure, this is not the fastest way (someone on the above referenced node timed the native find vs File::Find, with native winning by a factor of 5), but it's a way.

      also, be careful of the greps to remove the . and .. entries... it's legal to have directories that start with a period (or two, or more), so you have to do an exact match on both cases.

      (i think)

      i too am a newbie here, and i've been thanking people...
      hopefully, i can provide some answers myself one day.

      (ps: please forgive the expanded syntax, but it's (to my unPerlish eye) easier to read!)

        You are correct about . and .. - getting a regex to match them reliably is far trickier than it looks. The obvious m/^\.\.?$/, for instance, will give a false positive on "..\nsubdir". Much safer and simpler to just test on ($_ ne '.') && ($_ ne '..'). (BTW, != is numeric. Use ne for strings.)

        if (-d $_) && ($_ != '.') && ($_ != '..') {

        This is invalid syntax (needs an extra set of parens) and the != operator is not the one you want for string equality tests. I think you meant:

        if (-d and $_ ne '.' and $_ ne '..') {
        -d uses $_ if no argument is given.

        - Yes, I reinvent wheels.
        - Spam: Visit eurotraQ.
        

Re: Create a list of directories without . and ..
by vladb (Vicar) on Jun 04, 2002 at 18:36 UTC
    There's a pretty quick and dirty way to do it. Here's how:
    @a = grep(!/^.$/, `find .`); print @a;
    the find . system command will return a list of all directories (and sub-directories depending on command line switches used) starting at '.' (your current directory). By default, it will also return '.' as one item of the list. Here, you simply weed it out with a grep ;).

    _____________________
    $"=q;grep;;$,=q"grep";for(`find . -name ".saves*~"`){s;$/;;;/(.*-(\d+) +-.*)$/; $_=["ps -e -o pid | "," $2 | "," -v "," "];`@$_`?{print"+ $1"}:{print" +- $1"}&&`rm $1`; print$\;}