in reply to recursive mkdir

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 $!"); } }

Replies are listed 'Best First'.
Re^2: recursive mkdir
by afoken (Chancellor) on Dec 31, 2020 at 13:31 UTC
    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". ;-)