(tye)Re: recursive mkdir
by tye (Sage) on Jan 08, 2001 at 10:10 UTC
|
use File::Path qw( mkpath );
mkpath( $path, 0, 0777 );
And, no, I can't see this as a good case for using recursion. Sure, you could code it recursively, but the value of recursion is when it makes coding it easier. I think it would almost be a stretch to do this one recursively so you'd just be working hard to make your code slower. (:
FYI, see (tye)Re: Recursion for my thoughts on recursion.
This node has been updated.
-
tye
(but my friends call me "Tye") | [reply] [d/l] |
|
|
Thanks for the suggestion. I hadnt come across that module. Ill have to check it out, Im interested how the module does it.
I used recursion, because it was the only obvious way I could think of doing it. One question. How much slower could the code be when dealing with creating subdirectories? Since realisticly you are not going to create directories of say 100 deep. The script Im using it in seems to work quickly.
THANKS! zzSPECTREz
| [reply] |
|
|
Yeah, sorry, I was just noticing that you had coded it recursively. I didn't notice the recursion and had interpretted your posting as, in part, asking how you would go about rewriting it recursively (to learn about recursion). :-}
No, doing this recursively isn't going to make this unacceptably slow. I think the reason that you ended up with a recursive solution is that your first idea at how to loop through the list of directories went in the "wrong" order (or you chose this order because you wanted to be optimistic and assume that most of the time you don't need to create many directories so start from that end).
Recursion is one way to reverse a loop, but there is usually a "better" way. In fact, in Perl you can use the built-in "stacks" to reverse even the most hard to reverse loop via:
my @stack;
while( <> ) {
push @stack, $_;
}
while( @stack ) {
local( $_ )= pop @stack;
# your code here
}
And it is hard to argue that the above is worse than recursion in any way. ;)
-
tye
(but my friends call me "Tye") | [reply] [d/l] |
Re: recursive mkdir
by davorg (Chancellor) on Jan 08, 2001 at 13:44 UTC
|
If you're running on a Unix-like system, then you could
always use
system("mkdir -p $dir");
which will create all intermediate directories.
--
<http://www.dave.org.uk>
"Perl makes the fun jobs fun
and the boring jobs bearable" - me
| [reply] [d/l] |
|
|
| [reply] |
Re: recursive mkdir
by repson (Chaplain) on Jan 08, 2001 at 10:51 UTC
|
I'm not suggesting you continue writing the sub yourself,
but here's a way (probably not the best way) to write the
solution without using recursion (which should be saved for
when really needed).
sub my_mkdir {
my $path = shift;
my $perms = shift;
my @parts = split /\//, $path;
for my $num (1..$#parts) {
my $check = join('/', @parts[0..$num]);
unless (-d $check) {
mkdir( $check, $perms );
}
}
}
| [reply] [d/l] |
|
|
sub my_mkdir {
my ($path, $perms) = @_;
my $dir = '.';
for ( split /\//, $path ) {
mkdir $dir .= "/$_", $perms;
}
}
| [reply] [d/l] |
|
|
| [reply] |
Re: recursive mkdir
by chipmunk (Parson) on Jan 08, 2001 at 10:10 UTC
|
I think the best way would be the mkpath() function from File::Path. | [reply] |
Re: recursive mkdir
by a (Friar) on Jan 08, 2001 at 10:32 UTC
|
Those other monk's responses notwithstanding (see tye's recursion
link for an in-depth discussion) if you did want to go this route
(as a learning experience or something) your's is not
so bad a stab at it. You might want to look up merlyn's
discussions of '.*' (perhaps my ($parent) = $path =~ /([^\/]*)\//;
?) and don't you want to check the internal return of my_mkdir()?
Hmm, maybe not, save for debug/error msging.
Yoiks! I'm completely backwards here - You want
to be greedy. Dang recursion!Forget I mentioned it,... look,
out that window, why it's Supermunk! (slinks quietly away to chop
onions).
a | [reply] [d/l] |
|
|
Heh. The .* is correct here. The first call to my_mkdir matches all the parent directories, and each subsequent recursive call matches one fewer parent directory.
| [reply] |
|
|
I believe Im dealing with the return's properly. I want my routine to respond just like mkdir. Return 1 if succesfful and 0 if error and the error from mkdir still in $!.
Correct me if I got it wrong. Seems to test out right
zzspectrez
| [reply] |
Re: recursive mkdir
by Anonymous Monk on Feb 07, 2014 at 05:40 UTC
|
I have written this script to create directory within directory and have tested it.Its working properly and giving desired output.
for($i=1;$i<=10;$i++)
{
$a = $a."file$i";
$x = `mkdir $a`;
$a = $a."/";
$c = `cd $x`;
print "$c\n";
#$b = $a.$b
}
By Pragya Yadav ; Atish Pradhan and Pramod Kumar | [reply] |
Re: recursive mkdir
by cherio (Novice) on Dec 30, 2020 at 22:30 UTC
|
Well, who needs another subroutine but here it is anyway. It will create all parents except those sitting on top of the file system root "/"
sub dir_ensure {
for (@_) { # handles multiple DIRs
my $path = ($_ // die("Dir must be specified")) =~ s!/$!!sr;
next if -d $path; # DIR is already there
die("Path '$path' already exists and it's not a DIR") if -e _;
my $parent = $path =~ m"^(/[^/].*?)/(?!\.{1,2}$)[^/]+$"s
? $1 : die("Invalid path '$path'");
dir_ensure($parent); # ensure parent DIR exists
mkdir($path) or die("Failed to create DIR $path $!");
}
}
| [reply] [d/l] |
|
|
sub dir_ensure {
for (@_) { # handles multiple DIRs
my $path = ($_ // die("Dir must be specified")) =~ s!/$!!sr;
next if -d $path; # DIR is already there
die("Path '$path' already exists and it's not a DIR") if -e _;
my $parent = $path =~ m"^(/[^/].*?)/(?!\.{1,2}$)[^/]+$"s
? $1 : die("Invalid path '$path'");
dir_ensure($parent); # ensure parent DIR exists
mkdir($path) or die("Failed to create DIR $path $!");
}
}
Problems with that code:
- Recursion is not needed to split a path into a series of directories, as explained in other posts in this thread.
- The code assumes a single root directory. There are several operating systems that have more than one root directory. (DOS, Windows, OS/2, ...)
- There is a race condition: You stat() a part of the path way before you mkdir that part (see TOCTTOU). To avoid that problem, just call mkdir() and check its result. Expect EEXISTS for already existing directories.
- There is at least one module that already takes care of all those issues, plus OS-specific surprises: File::Path
Alexander
--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
| [reply] [d/l] |