recursive mkdir
$ mkdir -p foo/bar/zoo/andsoforth
Parameter p
stands for 'parents'.
Using mkdir -p
is a simple way for most modern OSes:
mkdir -p foo/bar/zoo/andsoforth
However, mkdir -p
is not recommended in many manuals. Read documentation for of GNU make
and autoconf
about problems with using mkdir -p
:
- http://www.gnu.org/savannah-checkouts/gnu/autoconf/manual/autoconf-2.69/html_node/Limitations-of-Usual-Tools.html#Limitations-of-Usual-Tools
- http://www.gnu.org/savannah-checkouts/gnu/make/manual/html_node/Utilities-in-Makefiles.html
The cross platform installation and configuration systems have their own safe alternatives for mkdir -p
.
CMake to use in shell command line:
cmake -E make_directory foo/bar/zoo/andsoforth
Autoconf to use in script with preprocessing:
AS_MKDIR_P(foo/bar/zoo/andsoforth)
or:
AC_PROG_MKDIR_P(foo/bar/zoo/andsoforth)
But these solutions require cmake
or autoconf
(M4
) tools to be installed (and possible preprocessing)
You can use also install-sh
script with -d
option:
install-sh -d foo/bar/zoo/andsoforth
This script is used by autoconf
and automake
project. I think it must be the safest solution.
At the time I was searching for a cross platform solution for standard /bin/sh
without dependences, but haven't found one. Therefore I wrote the next script that may be not ideal, but I think it is compliant to most cross platform requirements:
#! /bin/sh
cdirname() # cross platform alternative for 'dirname'
{
# $1 - path
test $# -eq 1 || { echo "Procedure 'cdirname' must have only one parameter. Scripting error."; exit 1; }
echo "$1" | sed -n -e '1p' | sed -e 's#//*#/#g' -e 's#\(.\)/$#\1#' -e 's#^[^/]*$#.#' -e 's#\(.\)/[^/]*$#\1#' -
}
mkd() # cross platform alternative for 'mkdir -p'
{
# $1 - directory to create
test $# -eq 1 || { echo "Function 'mkd' can create only one directory (with it's parent directories)."; exit 1; }
test -d "$1" && return 0
test -d "$(cdirname "$1")" || { mkd "$(cdirname "$1")" || return 1; }
test -d "$1" || { mkdir "$1" || return 1; }
return 0
}
This script can be used for old systems, where option -p
for mkdir
is absent.
sed
-based cross platform version of dirname
was added to the code. It works with a way similar to dirname
(correct with path /
, paths with base name only, paths with trailing /
, paths with and without trailing \n
s). This function can't work correct if the path has newlines or some invalid characters for current locale. It also replaces any combination of /
(//
, ///
) with single /
Changed line mkdir "$1" || return 1
to test -d "$1" || { mkdir "$1" || return 1; }
because mkdir
terminates with error if path exists and this check is needed for paths containing constructions like aaa\.
(If aaa
doesn't exist previous version creates aaa
and then tries to create it again).
This version of mkd doesn't generate an error if path already exist (but it still has the possibility to generate such an error in parallel execution) and can't get several directories in command line.