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

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

I am trying to search for directories within a given directory. If I use the following, then it only returns me the files within a directory:
parse_dir(`ls -l`)
I am supposed to write a function where I could pass the directory name and it will return a list of directories within..

Originally posted as a Categorized Question.

Replies are listed 'Best First'.
Re: How do I find directories within directories using : parse_dir(`ls -l`)
by japhy (Canon) on Aug 31, 2001 at 06:28 UTC
    If using parse_dir isn't a hard requirement, you can read directories using the normal, built-in means: readdir.
    opendir DIR, $path or die "can't read $path: $!"; @dirs = grep -d "$path/$_", readdir DIR; closedir DIR;
Re: How do I find directories within directories using : parse_dir(`ls -l`)
by toolic (Bishop) on Aug 15, 2009 at 18:14 UTC
    If you could use some other module, File::Slurp provides a read_dir function which can be used as follows.

    read_dir returns a list of directory contents.

    grep -d selects only directories (filtering out files).

    use File::Slurp; my @dirs = grep { -d "$dir/$_" } read_dir($dir);

    To include the . and .. special directories, add the keep_dot_dot option:

    my @dirs = grep { -d "$dir/$_" } read_dir($dir, keep_dot_dot=>1);
Re: How do I find directories within directories using : parse_dir(`ls -l`)
by RhetTbull (Curate) on Aug 31, 2001 at 19:13 UTC
    >I am supposed to write a function where I could pass the directory name
    That sounds awfully like homework to me but I'll give you the benefit of the doubt.
    Here's a solution that fits into your requirements but I would caution that japhy's solution above of using readdir is much better than your proposed solution of using backticks to run ls. Anyway, here it is.

    On my system, an ls -l produces something like this. It could be different on your system!:
    -rwxr-xr-x 1 rhettbull Domain U 294 Aug 31 10:59 dirs.pl drwxr-xr-x 2 rhettbull Domain U 0 Aug 31 10:58 testdir
    It's obvious that the directory entries start with a "d" as the first character on the line. So, we parse the lines looking for a "d" at the beginning of the line. Then we parse those lines with split. Notice that I limit split to 10 columns because the directory name might have spaces in it. I call split in list context and only grab the 10th entry (the directory name) since you didn't ask for the other stuff. Note that this will miss symlinks and I caution once again to use readdir.
    #!/bin/perl use strict; use warnings; my $lookhere = shift || '.'; parse_dir($lookhere); sub parse_dir { my $rootdir = shift || '.'; my @listing = `ls -l $rootdir`; foreach (@listing) { chomp; if (/^d/) { my $dir = (split /\s+/, $_, 10)[9]; print "$dir\n"; } } }

    Originally posted as a Categorized Answer.

Re: How do I find directories within directories using : parse_dir(`ls -l`)
by Codmate (Novice) on Mar 12, 2003 at 18:09 UTC
    You could hand-roll it as follows.

    Use ls to get a list of directories...

    chomp (my @dir = `ls $path`);
    ...and then test each entry to see whether it is a directory:
    my @list_of_directories = grep { -d "$path/$this_entry" } @dir;

      This is far from the "best" way. A much shorter (and less resource intensive, and more portable) method is:

      my @list_of_direcories = grep(-d, <$path/*>);

      We're not surrounded, we're in a target-rich environment!
        ...but the original poster said they had to use "ls".
Re: How do I find directories within directories using : parse_dir(`ls -l`)
by toolic (Bishop) on Aug 15, 2009 at 17:50 UTC
    Assuming you're using the parse_dir function from the File::Listing module...

    The following will populate the @dirs array with the names of the sub-directories in the current directory (excluding all hidden directories which begin with the dot character):

    use File::Listing qw(parse_dir); my @dirs = map { my( $name, $type ) = @$_; $type eq 'd' ? $name : () } + parse_dir(`ls -l`);

    To include 'dot' directories (except for the special . and .. directories), you'd simply use ls -la:

    my @dirs = map { my( $name, $type ) = @$_; $type eq 'd' ? $name : () } + parse_dir(`ls -la`);