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

This is driving me nuts. Let's say I have this string:
my $directory = "/home/user/files/personal/addresses";
I need to make that directory tree on another machine. I've played around with all kinds of stuff, and I can easily pop off the file name. But I'm getting stuck b/c you can't just say...
mkdir /home/user/file/personal
...and expect it to make it unless the previous directory is there. Not w/ unix anyway. If I knew the subdirectories would only go 3-4 layers deep, it wouldn't be a problem, but they could go on forever, so I need a more dynamic solution than what I've come up with. So, I'm hoping there's a module, or just something I'm missing that could help out. I found Find::File which made my life easier in gathering that info. Now I'm looking for a simpler way out of writing the directories.

Replies are listed 'Best First'.
•Re: Help making a directory tree
by merlyn (Sage) on Aug 26, 2003 at 07:50 UTC
      Or I could always go w/ Merlyn's solution. Quite brilliant. Thanks!
Re: Help making a directory tree
by wirrwarr (Monk) on Aug 26, 2003 at 08:09 UTC
    Just one off-topic note about unix's mkdir:
    At least the versions i'm using (GNU mkdir) support the "-p" flag to create missing parent directories.

    daniel.
      wirrwarr: That's definitely worth noting - I didn't know that. Unfortunately, the source is GNU friendly, and the target is Solaris. :(
Re: Help making a directory tree
by sgifford (Prior) on Aug 26, 2003 at 07:30 UTC
    I'm pretty sure there's a module to do this, but until somebody points it out you can try something like this:
    #!/usr/bin/perl -w use strict; mkdir_p($ARGV[0]); sub mkdir_p { my($d)=@_; my $dirsofar = ""; foreach my $dc (split(/\//,$d)) { next unless ($dc); $dirsofar .= "/".$dc; if (!mkdir($dirsofar)) { if ($! !~ /exists/i) { die "Couldn't mkdir($dirsofar): $!"; } } } }
      Thanks for the reply. One kicker here though. Your code stops when it can't make the first directory (/home in this case). Complains that the folder exists, which it will in most cases. I tried changing this:
      $dirsofar .= "/".$dc;
      to this:
      $dirsofar = ( $dirsofar =~ /^./ ) ? $dirsofar . "/".$dc : $dirsofar .= + $dc;
      In order to make directories only from the current directory. IE - if running the script from /home/user --- make the other two directories. But in that case if:
      @ARGV[0] = "/home/user/files/work/file";
      My directories would turn out to be:
      /home/useruser/filesfilesfiles/workworkworkwork
      Another 20 minutes and I should be able to to tweak your guy... I gotta bolt in a minute though. :(
        Merlyn's solution is better, but the directory already existing is why it checks the error message:
        if ($! !~ /exists/i) { die "Couldn't mkdir($dirsofar): $!"; }
        As long as the error message contains the word "exists", it will just ignore the error and continue on. I tested this case, and it worked fine for me. If it doesn't work for you, I'm curious what error message it prints...