Is there a linux command that I'm overlooking that makes it possible to do something along the lines of: (pseudo)
$ mkdir -R foo/bar/zoo/andsoforth
Or is there no alternative but to make the directories one at a time?
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
:
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.
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
– Роман Коптев
Apr 17 '16 at 23:13
mkdir -p
would be too old (and we're talking at least a couple of decades old) to have a printf
utility or support --
to mark the end of options.
– Stéphane Chazelas
Apr 18 '16 at 14:06
printf -- "$1\n"
is wrong. The first non-option argument to printf is the format. It should be printf '%s\n' "$1"
– Stéphane Chazelas
Apr 18 '16 at 14:10
printf
is marked as one of the safest functions and must be present even in minimal shell installation. It's more safe then using echo
as echo
uses different options on some platforms and has a question with the newline. About "--" I can't say 100% from there it started to be used. It can be omited. It is here for safety only.
– Роман Коптев
Apr 18 '16 at 14:12
cdirname
would give the wrong answer for foo/bar//
, or directory names containing newline characters, or invalid characters in the current locale.
– Stéphane Chazelas
Apr 18 '16 at 14:12
printf
is safe on POSIX systems. POSIX systems support mkdir -p
. mkdir -p
has been specified by POSIX for decades. --
started to be widespread on AT&T systems starting with SysIII in the early-mid-80s. printf
first appeared as a ksh
builtin I believe and was specified by POSIX later than mkdir -p
. Some POSIX shells (like pdksh or yash based) still don't have printf
builtin.
– Stéphane Chazelas
Apr 18 '16 at 14:28
mkdir -p
is the race condition in simultaneous execution of mkdir -p a/b
and mkdir -p a/c
, where both see a/
needs to be created, but the second process to call mkdir(2)
finds that the other process has already created it. That isn't a concern in interactive use, and it certainly isn't "a few systems don't support it." Further, I don't think gnu make docs on on what utilities to use in makefiles is appropriately applied beyond that context. What's more likely to be present, mkdir
that supports -p
, or autoconf
?. For me, the former.
– Tim B
Apr 18 '16 at 15:09
autoconf
doc makes sense (but bear in mind that autoconf
's target includes very old systems), that make
documentation (actually that section comes from gnustandards, not make) doesn't make much sense. printf
was added without much of a justification to that OK list in 2010.
– Stéphane Chazelas
Apr 18 '16 at 15:23
mkdir -p
. I've read many manuals that say don't use mkdir -p
. 2. The recommended rules of make files doesn't recommend using mkdir -p
and I follow them. I need only at least unix make working on the platform for my projects, and I don't interesting for systems that doesn't support make files and their minimal syntax as written in make documentation. At this point the question must be closed.
– Роман Коптев
Apr 18 '16 at 15:24
mkdir -p
is not cross platform is wrong and misleading. I still believe it is.
– Tim B
Apr 18 '16 at 15:30
Option -p
in command mkdir
makes parent directories as needed (no error if existing):
mkdir -p foo/bar/zoo/andsoforth
Another way is, for example using &&
(error if the specified folder exists):
mkdir foo && mkdir foo/bar && mkdir foo/bar/zoo && mkdir foo/bar/zoo/andsoforth
The chaining operator &&
is used to chain commands together, such that the next command is run if and only if the preceding command exited without errors.
Of course, the first way is better.
mkdir -p foo/{bar,baz}/zoo/andsoforth
. Very useful! – Aaron Copley Aug 07 '12 at 20:43mkdir
has only 6 documented flags in total. Hell, I feel like the command should create directories recursively by default, and if you don't want this then you should have to specify so explicitly. – jbowman May 13 '16 at 18:03