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

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

I am trying to get a script to check to see if a folder exists and if it does not create it. Now I am sure this is basic for you guys but to me it is all new and hard. The code I am using is this:
if (!-d "e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game") +{ mkdir("e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game" +); } if (!-d "e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game/$S +ubSet") { mkdir("e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game/ +$SubSet"); } if (!-d "e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game/$S +ubSet/thmb") { mkdir("e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game/ +$SubSet/thmb"); }
The code looks fine to me but maybe someone else can see what I am doing wrong.

Replies are listed 'Best First'.
Re: Creating new folders
by plobsing (Friar) on Feb 03, 2008 at 03:20 UTC
    A couple things:
    • If you aren't woried about error results of mkdir (maybe you should be, but you aren't checking right now), you don't need to check if the directory exists. If it exists, the function returns an error (which you don't check, so to you it won't make a difference).
    • the File::Path core module contains a nice function called mkpath which recursively checks parent dirs to make sure they exist before making the directory of interest
    • Long path values should be kept in a constant or a variable somewhere
    • if(! ...) is better written as unless( ... ), this is more of a personal style thing, but at least use if (not ... ) as both are more readable
    Here's how I'd do it:
    use File::Path 'mkpath'; use constant DIR => 'e:/web/public_html/eagle_f91...'; unless (-d DIR) { mkpath(DIR) or die "Could not mkpath: $!\n" }
Re: Creating new folders
by grep (Monsignor) on Feb 03, 2008 at 03:13 UTC
    You should always test your file operations.

    Try this:

    if (!-d "e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game") +{ mkdir("e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game" +) or die("$!\n"); } if (!-d "e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game/$S +ubSet") { mkdir("e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game/ +$SubSet") or die("$!\n"); } if (!-d "e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game/$S +ubSet/thmb") { mkdir("e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game/ +$SubSet/thmb") or die("$!\n"); }
    $! will show you the specific error message.

    UPDATE: fixed typo

    grep
    One dead unjugged rabbit fish later...
      Thanks I had forgoten about the die command, but in this case it did not help.
        It's not really the die that's important. It's the test of file operation and the printing of $!. You could just as easily write:
        if (!-d "e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game") +{ mkdir("e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game" +) or print "$!\n"; }
        If there's an error it should populate $!, that error message will tell you what went wrong (generally). So it should either work or give you and error. So it has to help.

        grep
        One dead unjugged rabbit fish later...
Re: Creating new folders
by kyle (Abbot) on Feb 03, 2008 at 04:26 UTC

    My usual way to ensure that a directory exists is:

    my $dir = ...; if ( ! -d $dir && ! mkdir $dir ) { die "Can't mkdir '$dir': $!"; }

    This reads fairly naturally to me as "if it's not there, and I can't make it, die with a good error message." If you're concerned that the directory above the one you want might not be there (and therefore would block you trying to create the one you want), look at mkpath in File::Path.

    For your particular case, where you want to do this with multiple directories, I'd probably put the directories in a list and then loop over that.

    my @wanted_directories = ( "e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game", "e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game/$S +ubSet", "e:/web/public_html/eagle_f91/ffinfo/protected/images/$Game/$S +ubSet/thmb" ); foreach my $dir ( @wanted_directories ) { if ( ! -d $dir && ! mkdir $dir ) { die "Can't mkdir '$dir': $!"; } }
      In general I try very hard to avoid the race condition that come from assuming the result of a filetest operator remains valid. In this case it is possible that something creates the directory between the moment of the -d and the mkdir and that's a case I'd prefer to work instead of fail. In many real cases this is impossible or not an issue of course, but I still prefer my code to be able to handle such cases. So normally I'd write:
      if (!mkdir($dir)) { my $err = $!; die "Could not create $dir: $err" unless -d $dir; }
Re: Creating new folders
by ww (Archbishop) on Feb 03, 2008 at 03:25 UTC
    Can't reproduce the problem under W2k and AS 5.8.8.

    perl -v
    This is perl, v5.8.8 built for MSWin32-x86-multi-thread
    (with 33 registered patches, see perl -V for more detail)
    ...
    Binary build 819 [267479] provided by ActiveState http://www.ActiveState.com Built Aug 29 2006 12:42:41

    OP's path is only 62 chars, at most, so that's not the issue. So, starting with no directory, "test," extant in C:\

    C:\>dir t* ... Directory of C:\ 09/04/2006 11:26a <DIR> TEMP 0 File(s) 0 bytes 1 Dir(s) 10,945,437,696 bytes free

    Quoting varied from OP's, solely (AFAIK) because the following is run as a one-liner:

    C:\>perl -e "if (!-d 'c:/test') {mkdir 'c:/test1';}" C:\>dir t* ... Directory of C:\ 09/04/2006 11:26a <DIR> TEMP 02/02/2008 10:14p <DIR> test1 0 File(s) 0 bytes 2 Dir(s) 10,945,437,696 bytes free

    ...and, further variance this time in both quoting and slash direction:

    C:\>perl -e "if (!-d 'c:/test') {mkdir \"c:/test\";}" C:\>dir t* ... Directory of C:\ 09/04/2006 11:26a <DIR> TEMP 02/02/2008 10:17p <DIR> test 02/02/2008 10:14p <DIR> test1 0 File(s) 0 bytes 3 Dir(s) 10,945,404,928 bytes free

    So, are you sure your code is not working? ...sure that E:\ exists and is writable? ... Update - addition ...sure that all the dirs between E:\ and the first you're trying to create actually exist? (See the second bullet in plobsing's reply, above.)

      I know it was not working when I wrote this post as I tried and it did not create the errors. But when I tried agin (afte adding the die command to get errors) everything worked fine. Not sure what was going on
        Not sure what was going on

        There are several possibilities, but the most important lesson to learn from this is always record your error messages. Error messages are your friends.

        Three common errors beginners make on Windows:
        1. Failing to save their script edits.
        2. Saving to the wrong folder, i.e. running a different version of the script to the one they are editing.
        3. Failing to refresh Windows Explorer. Your script may have actually worked first time, but if you checked with a GUI it might not have given an up-to-date view.
Re: Creating new folders
by apl (Monsignor) on Feb 03, 2008 at 18:55 UTC
    Building on what plobsing said, I'd suggest
    use File::Path 'mkpath'; CreateIfNotPresent( "e:/web/public_html/eagle_f91/ffinfo/protected/ima +ges/$Game" ); CreateIfNotPresent( "e:/web/public_html/eagle_f91/ffinfo/protected/ima +ges/$Game/$SubSet" ); CreateIfNotPresent( "e:/web/public_html/eagle_f91/ffinfo/protected/ima +ges/$Game/$SubSet/thmb" ); sub CreateIfNotPresent { my ( $dir ) = @_; unless (-d $dir) { mkpath($dir) or die "Could not mkpath '$dir': $!\n" } }