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

How do I test if a certain directory exists or not? I need this because if the directory does not exist, I need to create it.

Also, is it possible for the script to go into a certain directory and return all of the names of the subdirectories in that directory?

Thanks.

Zenon Zabinski | zdog | zdog7@hotmail.com

Replies are listed 'Best First'.
Re: Checking for Directories
by btrott (Parson) on Jul 28, 2000 at 23:22 UTC
    You can check if a directory exists using -e, and if it's a directory using -d. So you can probably just use the latter:
    print "is directory" if -d "/foo/bar";
    For your second question:
    opendir DH, "/foo/bar" or die $!; my @subdirs = grep -d, readdir DH; closedir DH or die $!;
    Sub-directories are in @subdirs.

    Umm, embarrassing update: read chip's answer below for why my second answer is broken. So use his code.

      Sorry, btrott, that won't work ... readdir() only returns basenames, and that's not enough for -d to work. Besides, you probably don't want to count '.' and '..'. How about:

      my $dir = '/foo/bar'; opendir DH, $dir or die $!; my @subdirs = grep { -d } map { "$dir/$_" } grep { $_ ne '.' && $_ ne '..' } readdir DH; closedir DH;

          -- Chip Salzenberg, Free-Floating Agent of Chaos

        If the debugger is accurate, you are stepping through the array three times to produce your results. If you have a directory with a large number of files in it, this is not the most runtime-efficient way of doing it.

        This version makes a single pass through the directory listing.

        #Assume all the open code foreach( readdir DH ) { next if ( $_ eq '.' or $_ eq '..' ); push @subdirs, "$dir/$_" if ( -d "$dir/$_" ); }
        Of course, you may still not like this. It will be kinda hungry on memory, especially if the ratio of files to directories is very large - the foreach will suck in every file at once. It may be better to try it with a while loop - it will be easier on memory but will take longer due to buffering issues.
        mikfire
        Oops. Thanks for the reminder. My test script was running in the same directory that I was opendir-ing. Stupid, but oh well. :)
      Or you could try something like this.
      my @n = grep { -d $_ } <*>;
Don't Check for Directories
by chip (Curate) on Jul 29, 2000 at 00:32 UTC
    I just noticed your purpose. I recommend that if you want to create a directory if it's missing, just go ahead and call the mkdir operator every time the program runs. The mkdir may fail if the directory is there, but who cares? It's not like there's any penalty for setting $!. :-)

        -- Chip Salzenberg, Free-Floating Agent of Chaos

      Ah, but the sticky bit there is that you want to ignore a failure due to "directory already exists" and not ignore any other reasons for failure, including "file already exists". Before Errno.pm, this was tricky. Now it isn't so bad except that "file already exists" and "directory already exists" put the same value in $!.

      So I think the easiest robust solution is still to only create the directory if it doesn't already exists.

        Well, I still don't see the point in checking ... after all, what's the next thing you'll do? That's right, create a file in the directory ... and whatever the error is, you can report it.

        Besides, why introduce a race condition without having to?

            -- Chip Salzenberg, Free-Floating Agent of Chaos

RE: Checking for Directories
by eLore (Hermit) on Jul 28, 2000 at 23:24 UTC
    One can use the -d "dirname" test. from the command line:
    perl -e "-d (\"/tmp\") and print \"aack\n\"";
    in a script:
    #!/usr/local/bin/perl -d "/tmp" and print "/tmp is a directory\n";
      Just for future reference, you can mix quotation mark styles on the command line, eliminating the escapes.
      $ perl -e "-d (\"/tmp\") and print \"aack\n\""
      becomes
      $ perl -e '-d ("/tmp") and print "aack\n"'
Re: Checking for Directories
by Anonymous Monk on Jul 29, 2000 at 00:23 UTC

    Given a list of directories to be checked or made, this will return a list of directories made. (@dirs NOT @created) is the list of directories which already exist. If you @dirs don't have a full path, use chdir.

    my @created = grep { (!-d) && mkdir($_,oct(777)) } @dirs;
    
RE: Checking for Directories
by Anonymous Monk on Jul 28, 2000 at 23:53 UTC
    -x $file does it exist foreach your way through a directory handel testing w/ (-x $file && -d $file) to test for subdirectories ... pop em ont an aray or whatever to store the vals