ZetCode

Linux mkdir Command

last modified October 23, 2026

The mkdir (make directory) command creates directories. It can create one or several directories at once, build a whole path of nested directories, and set the permissions of the new directories.

The syntax is mkdir [options] directory.... The examples use GNU mkdir from coreutils 9.1 with Bash 5.2. The most important options are -p (create parents, no error if the directory exists), -m (set the mode), and -v (print each created directory).

Creating a directory

With a single argument, mkdir creates one directory in the current working directory.

mkdir projects
ls -ld projects

mkdir prints nothing on success. The -d option of ls lists the directory itself instead of its contents. The new directory is owned by the user who created it, and its permissions come from the umask, which is covered later.

$ mkdir projects
$ ls -ld projects
drwxr-xr-x 2 jano jano 4096 Oct 23 13:22 projects

Creating multiple directories

Each argument is a separate directory.

mkdir docs images scripts
ls

The three directories are created in the order given. If one of them cannot be created, mkdir reports an error, continues with the rest, and exits with a non-zero status.

$ mkdir docs images scripts
$ ls
docs
images
projects
scripts

When the directory already exists

Creating a directory that already exists is an error, unless the -p option is used.

mkdir docs
echo $?
mkdir -p docs
echo $?

Without -p, the command fails with exit status 1. With -p, an existing directory is silently accepted. This makes mkdir -p the usual choice in scripts that may run more than once.

$ mkdir docs
mkdir: cannot create directory ‘docs’: File exists
$ echo $?
1
$ mkdir -p docs
$ echo $?
0

Creating nested directories

By default, all parent directories of the new directory must exist. The -p (--parents) option creates the missing parents.

mkdir app/src/main
mkdir -p app/src/main
tree app

The first command fails because app and app/src do not exist. The second creates all three levels in one step.

$ mkdir app/src/main
mkdir: cannot create directory ‘app/src/main’: No such file or directory
$ mkdir -p app/src/main
$ tree app
app
└── src
    └── main

3 directories, 0 files

Verbose output

The -v (--verbose) option prints a message for each directory that is created.

mkdir -pv website/{css,js,img}
mkdir -pv website/css

The braces are expanded by the shell, not by mkdir: website/{css,js,img} becomes three arguments. With -p, the parent website is created first and also reported. The second command prints nothing, because website/css already exists and no directory was created.

$ mkdir -pv website/{css,js,img}
mkdir: created directory 'website'
mkdir: created directory 'website/css'
mkdir: created directory 'website/js'
mkdir: created directory 'website/img'
$ mkdir -pv website/css

Creating a directory tree with brace expansion

Brace expansion can produce many paths from a short pattern. Combined with -p, a whole tree is created at once.

mkdir -p backup/2026/{01..03}/{logs,db}

The sequence {01..03} expands to 01 02 03 with the leading zeros kept, and each month gets a logs and a db directory. To preview the paths, put echo in front of the command.

$ mkdir -p backup/2026/{01..03}/{logs,db}
$ tree backup
backup
└── 2026
    ├── 01
    │   ├── db
    │   └── logs
    ├── 02
    │   ├── db
    │   └── logs
    └── 03
        ├── db
        └── logs

11 directories, 0 files

Setting permissions

New directories get the mode 777 minus the bits set in the umask. The -m (--mode) option sets the mode explicitly, in numeric or symbolic form.

umask
mkdir default
mkdir -m 700 secret
mkdir -m u=rwx,g=rx,o= shared
ls -ld default secret shared

With the umask 0022, a plain mkdir creates the directory with mode 755 (rwxr-xr-x). The secret directory is accessible only by its owner, and shared can be entered and listed by the group but not by others. Setting the mode at creation avoids the short window during which a directory created first and changed later with chmod has the default permissions.

$ umask
0022
$ mkdir default
$ mkdir -m 700 secret
$ mkdir -m u=rwx,g=rx,o= shared
$ ls -ld default secret shared
drwxr-xr-x 2 jano jano 4096 Oct 23 13:22 default
drwx------ 2 jano jano 4096 Oct 23 13:22 secret
drwxr-x--- 2 jano jano 4096 Oct 23 13:22 shared

Mode and parent directories

When -m is combined with -p, the mode applies only to the last directory in the path.

mkdir -p -m 700 vault/keys/ssh
ls -ld vault vault/keys vault/keys/ssh

The parents vault and vault/keys get the default mode from the umask. If all levels must be private, set a stricter umask in a subshell, for example (umask 077; mkdir -p vault/keys/ssh), or run chmod on each level.

$ mkdir -p -m 700 vault/keys/ssh
$ ls -ld vault vault/keys vault/keys/ssh
drwxr-xr-x 3 jano jano 4096 Oct 23 13:22 vault
drwxr-xr-x 3 jano jano 4096 Oct 23 13:22 vault/keys
drwx------ 2 jano jano 4096 Oct 23 13:22 vault/keys/ssh

Names with spaces

The shell splits arguments on spaces, so a directory name with spaces must be quoted or escaped.

mkdir My Documents
ls -d My Documents
rmdir My Documents
mkdir "My Documents" 'Old Files' Tax\ 2026
ls -d My* Old* Tax*

The unquoted command creates two directories, My and Documents, which are removed again with rmdir. Double quotes, single quotes, and a backslash before the space all produce a single name. In scripts, always quote variables: mkdir -p "$dir".

$ mkdir My Documents
$ ls -d My Documents
Documents
My
$ rmdir My Documents
$ mkdir "My Documents" 'Old Files' Tax\ 2026
$ ls -d My* Old* Tax*
My Documents
Old Files
Tax 2026

Common errors

These are the errors you are most likely to see with mkdir.

touch notes
mkdir notes
mkdir notes/drafts
mkdir /opt/myapp
sudo mkdir /opt/myapp
sudo chown jano: /opt/myapp
ls -ld /opt/myapp

A directory cannot have the same name as an existing file, and a file cannot be used as a parent directory. Creating a directory requires write permission on the parent directory; /opt is owned by root, so the directory is created with sudo and then handed over to the regular user with chown.

$ touch notes
$ mkdir notes
mkdir: cannot create directory ‘notes’: File exists
$ mkdir notes/drafts
mkdir: cannot create directory ‘notes/drafts’: Not a directory
$ mkdir /opt/myapp
mkdir: cannot create directory ‘/opt/myapp’: Permission denied
$ sudo mkdir /opt/myapp
$ sudo chown jano: /opt/myapp
$ ls -ld /opt/myapp
drwxr-xr-x 2 jano jano 4096 Oct 23 13:22 /opt/myapp

Temporary directories

For scratch work in scripts, use mktemp -d instead of mkdir with a fixed name.

dir=$(mktemp -d)
echo "$dir"
ls -ld "$dir"
rmdir "$dir"

mktemp -d creates a directory with a unique random name under /tmp and mode 700, and prints its path. A fixed name such as /tmp/work can collide with another run of the script or be created in advance by another user.

$ dir=$(mktemp -d)
$ echo "$dir"
/tmp/tmp.Vz6FNryKg1
$ ls -ld "$dir"
drwx------ 2 jano jano 4096 Oct 23 13:22 /tmp/tmp.Vz6FNryKg1
$ rmdir "$dir"

Using mkdir in a script

The script creates the layout of a new project. It can be run repeatedly and reports a failure.

mkdirs.sh
#!/bin/bash

# create the directory layout of a new project; safe to run repeatedly
project=${1:-demo}

if ! mkdir -p "$project"/{src,tests,docs}; then
    echo "cannot create $project" >&2
    exit 1
fi

echo "created $project"

Because of -p, the second run succeeds without changing anything. When the target exists as a regular file, mkdir fails once for each of the three paths, the if ! branch prints a message, and the script exits with status 1.

$ bash mkdirs.sh webapp
created webapp
$ bash mkdirs.sh webapp
created webapp
$ tree webapp
webapp
├── docs
├── src
└── tests

4 directories, 0 files
$ touch report
$ bash mkdirs.sh report
mkdir: cannot create directory ‘report’: Not a directory
mkdir: cannot create directory ‘report’: Not a directory
mkdir: cannot create directory ‘report’: Not a directory
cannot create report
$ echo $?
1

Best practices for mkdir

Source

GNU mkdir manual

In this article, we have used the mkdir command to create single and nested directories, set their permissions, handle names with spaces, and create directories safely in scripts.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Linux tutorials.