/flags/coreutils/mkdir-p
mkdir -p: create parent directories and ignore existing ones
- 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
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 | sortOutput
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
| Option | Effect |
|---|---|
| -p, --parents | Create missing parents; an existing directory is not an error |
| -v, --verbose | Print a line for each directory actually created |
| -m MODE, --mode=MODE | Mode 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:
mkdir -p project
mkdir -pv project/src/lib/utilOutput
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
mkdir -p app/{src,tests,docs} app/src/{api,ui}
find app -type d | sortOutput
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.
-ponly ignores existing directories. If any component of the path is a regular file,mkdir -pexits 1 withNot a directoryorFile exists. - It hides typos. Because existing directories are accepted silently,
mkdir -p /var/lib/myaphappily creates a misspelled tree. Add-vwhen you want to see what was created. - Permissions of parents.
-mapplies 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.
touch config
mkdir -p config/nestedOutput · 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.