Skip to content

/flags/coreutils/mkdir-p

mkdir -p: create parent directories and ignore existing ones

verified onenvironmentlocal · windows 10.0.26200 arm64 · GNU bash 5.3.15 (Git Bash) · ls (GNU coreutils) 8.32updated
tool
GNU coreutils
command
mkdir
flag
-p, --parents
default
off (a missing parent or an existing directory is an error)

mkdir -p path/to/dir creates every missing directory along the path and does nothing, without an error, for the parts that already exist. Without -p, mkdir creates only the last component: it fails with No such file or directory when a parent is missing, and with File exists when the target is already there. That makes -p the safe, idempotent form for scripts, Dockerfiles and CI steps that may run more than once.

Without and with -p

bash
mkdir a/b/c; echo "exit: $?"
mkdir -p a/b/c; echo "exit: $?"
mkdir -p a/b/c; echo "exit (second run): $?"
mkdir a/b/c; echo "exit (exists, no -p): $?"
find a | sort

Output

mkdir: cannot create directory ‘a/b/c’: No such file or directory
exit: 1
exit: 0
exit (second run): 0
mkdir: cannot create directory ‘a/b/c’: File exists
exit (exists, no -p): 1
a
a/b
a/b/c

The first call fails because a and a/b do not exist. The second creates all three levels. Running it again succeeds, while plain mkdir on the existing directory reports File exists, the error explained in mkdir: cannot create directory: File exists.

Options that go with -p

OptionEffect
-p, --parentsCreate missing parents; an existing directory is not an error
-v, --verbosePrint a line for each directory actually created
-m MODE, --mode=MODEMode of the last directory only, not of the parents
(none)Create one directory; its parent must exist and it must not exist

-v shows which levels were new, which helps when debugging a setup script:

bash
mkdir -p project
mkdir -pv project/src/lib/util

Output

mkdir: created directory 'project/src'
mkdir: created directory 'project/src/lib'
mkdir: created directory 'project/src/lib/util'

Only the three missing directories are listed; project already existed and is skipped silently.

Create several trees at once

bash
mkdir -p app/{src,tests,docs} app/src/{api,ui}
find app -type d | sort

Output

app
app/docs
app/src
app/src/api
app/src/ui
app/tests

The braces are expanded by the shell, not by mkdir: each word becomes a separate path argument. In sh or dash brace expansion does not exist, so a directory literally named {src,tests,docs} would be created; list the paths explicitly there.

Pitfalls

  • A file in the way still fails. -p only ignores existing directories. If any component of the path is a regular file, mkdir -p exits 1 with Not a directory or File exists.
  • It hides typos. Because existing directories are accepted silently, mkdir -p /var/lib/myap happily creates a misspelled tree. Add -v when you want to see what was created.
  • Permissions of parents. -m applies only to the final directory; parents get the umask defaults.
  • Not a test. Exit 0 does not mean the directory is writable; check with [ -w dir ] if the next step writes there.
bash
touch config
mkdir -p config/nested

Output · exit 1

mkdir: cannot create directory ‘config’: Not a directory

Here config is a file, so -p cannot help: remove or rename the file first.

FAQ

Does mkdir -p fail if the directory already exists?

No. With -p an existing directory is not an error, so the command exits 0 and changes nothing. That is why scripts use mkdir -p instead of testing with [ -d dir ] first. It still fails when the path exists as a regular file.

Does mkdir -p -m 700 apply the mode to every directory?

No. -m sets the mode only on the last directory of the path. Parents that -p creates get the default mode from the umask, plus write and search permission for the owner. Run chmod on the parents if they need a stricter mode.

Is mkdir -p portable?

Yes. -p is part of POSIX, so it works the same in GNU coreutils, BusyBox, macOS and the BSDs. The long form --parents is a GNU extension; -v (--verbose) is not in POSIX either, although macOS mkdir has it.

Sources