πŸ“ mkdir Command

Creating Directories in Linux/UNIX Systems

Overview

The mkdir (make directory) command creates new directories in the filesystem. While seemingly simple, mkdir offers powerful options for creating directory structures, setting permissions, handling errors, and providing verbose output. Understanding mkdir's capabilities is fundamental to filesystem management and scripting in Linux/UNIX environments.

Syntax: mkdir [OPTIONS] directory_name...

The mkdir command creates directories with names specified as arguments. It can create single directories, multiple directories at once, or entire directory hierarchies with nested subdirectories.

Example 1

Creating a Single Directory

$ ls file1.txt file2.txt $ mkdir projects $ ls -l drwxr-xr-x 2 craig staff 64 Nov 7 12:00 projects -rw-r--r-- 1 craig staff 42 Nov 7 11:55 file1.txt -rw-r--r-- 1 craig staff 38 Nov 7 11:56 file2.txt $ cd projects $ pwd /home/craig/projects

What's Happening:

The most basic use of mkdir creates a single directory in the current location. The new directory is created with default permissions (typically 755, modified by your umask). The 'd' at the start of the permissions indicates it's a directory. You can then navigate into it using cd.

Default Permissions: New directories typically get rwxr-xr-x (755) permissions, but this is affected by the umask setting. Check with: umask
Example 2

Creating Multiple Directories Simultaneously

$ mkdir dir1 dir2 dir3 dir4 $ ls -l drwxr-xr-x 2 craig staff 64 Nov 7 12:05 dir1 drwxr-xr-x 2 craig staff 64 Nov 7 12:05 dir2 drwxr-xr-x 2 craig staff 64 Nov 7 12:05 dir3 drwxr-xr-x 2 craig staff 64 Nov 7 12:05 dir4 # Create directories with descriptive names: $ mkdir backups documents downloads music photos videos # Using brace expansion: $ mkdir project{1,2,3,4,5} $ ls project1 project2 project3 project4 project5 # Sequential numbering: $ mkdir test{01..10} $ ls test01 test02 test03 test04 test05 test06 test07 test08 test09 test10

What's Happening:

Mkdir accepts multiple directory names as arguments, creating all of them in a single command. This is much more efficient than running mkdir repeatedly. Bash brace expansion provides powerful shortcuts for creating numbered or patterned directory names. The syntax {1,2,3} creates specific names, while {01..10} creates sequential ranges with zero-padding.

Pro Tip: Brace expansion works before mkdir runs, so mkdir {a,b,c}{1,2} creates a1, a2, b1, b2, c1, c2.
Example 3

Creating Parent Directories with -p (Path)

# Without -p, this fails if parent doesn't exist: $ mkdir projects/web/frontend/components mkdir: cannot create directory 'projects/web/frontend/components': No such file or directory # With -p, creates entire path: $ mkdir -p projects/web/frontend/components $ tree projects projects └── web └── frontend └── components 3 directories, 0 files # Create complex directory structure: $ mkdir -p company/{hr,it,sales}/{2023,2024,2025}/{q1,q2,q3,q4} $ tree company company β”œβ”€β”€ hr β”‚ β”œβ”€β”€ 2023 β”‚ β”‚ β”œβ”€β”€ q1 β”‚ β”‚ β”œβ”€β”€ q2 β”‚ β”‚ β”œβ”€β”€ q3 β”‚ β”‚ └── q4 β”‚ β”œβ”€β”€ 2024 [same structure] β”‚ └── 2025 [same structure] β”œβ”€β”€ it [same structure] └── sales [same structure] # Also safe if directory already exists: $ mkdir -p projects/web # No error, does nothing

What's Happening:

The -p (parents) flag is one of mkdir's most useful options. It creates any missing parent directories in the path automatically. Without -p, mkdir fails if any parent directory doesn't exist. Additionally, -p makes mkdir idempotentβ€”it won't error if the directory already exists, making it perfect for scripts.

Scripting Essential: Always use mkdir -p in scripts to avoid failures from directories that might already exist.
Example 4

Setting Permissions with -m (Mode)

# Create directory with specific permissions: $ mkdir -m 700 private_data $ ls -ld private_data drwx------ 2 craig staff 64 Nov 7 12:10 private_data # Only owner can read, write, execute # Create with group write permissions: $ mkdir -m 770 shared_team $ ls -ld shared_team drwxrwx--- 2 craig staff 64 Nov 7 12:11 shared_team # Owner and group have full access # Public read-only directory: $ mkdir -m 755 public_docs $ ls -ld public_docs drwxr-xr-x 2 craig staff 64 Nov 7 12:12 public_docs # Symbolic mode: $ mkdir -m u=rwx,g=rx,o=rx standard_dir $ ls -ld standard_dir drwxr-xr-x 2 craig staff 64 Nov 7 12:13 standard_dir # Create private directory with parents: $ mkdir -pm 700 ~/.config/app/data $ ls -ld ~/.config/app/data drwx------ 2 craig staff 64 Nov 7 12:14 /home/craig/.config/app/data

What's Happening:

The -m (mode) flag sets permissions during directory creation, avoiding a separate chmod command. Permissions can be specified in octal (like 755) or symbolic notation (u=rwx,g=rx,o=rx). This is more secure than creating a directory and then changing permissions, as there's no window where the directory has default permissions. The -m flag can be combined with -p.

Security Note: When creating sensitive directories, always use mkdir -m 700 to ensure they're immediately protected.
Example 5

Verbose Output with -v

$ mkdir -v test_directory mkdir: created directory 'test_directory' $ mkdir -pv project/src/main/java/com/company/app mkdir: created directory 'project' mkdir: created directory 'project/src' mkdir: created directory 'project/src/main' mkdir: created directory 'project/src/main/java' mkdir: created directory 'project/src/main/java/com' mkdir: created directory 'project/src/main/java/com/company' mkdir: created directory 'project/src/main/java/com/company/app' # Multiple directories: $ mkdir -v dir1 dir2 dir3 mkdir: created directory 'dir1' mkdir: created directory 'dir2' mkdir: created directory 'dir3' # In scripts for logging: $ mkdir -pv /var/log/myapp/{info,warning,error} 2>&1 | tee -a setup.log mkdir: created directory '/var/log/myapp' mkdir: created directory '/var/log/myapp/info' mkdir: created directory '/var/log/myapp/warning' mkdir: created directory '/var/log/myapp/error'

What's Happening:

The -v (verbose) flag makes mkdir print a message for each directory created. This is invaluable for debugging scripts, creating audit trails, and understanding what's happening when creating complex directory structures. When combined with -p, you see every directory in the path being created. Verbose output can be redirected to log files for documentation.

Best Practice: Use -v in installation and setup scripts to document what directories were created.
Example 6

Creating Dated Directory Structures

# Create directory with current date: $ mkdir backup-$(date +%Y-%m-%d) $ ls backup-2025-11-07 # Timestamp with time: $ mkdir log-$(date +%Y%m%d-%H%M%S) $ ls log-20251107-120530 # Organized archive structure: $ mkdir -p archive/$(date +%Y)/$(date +%m) $ tree archive archive └── 2025 └── 11 # Monthly backup directories: $ mkdir -p backups/{2024,2025}/{01..12} $ ls backups/2025 01 02 03 04 05 06 07 08 09 10 11 12 # Weekly project structure: $ for week in {1..52}; do mkdir -p projects/2025/week$(printf "%02d" $week) done # Daily log directories: $ mkdir -p logs/$(date +%Y/%m/%d) $ ls -R logs logs: 2025 logs/2025: 11 logs/2025/11: 07

What's Happening:

Using command substitution with $(date) creates dynamically named directories based on the current date and time. This is essential for automated backup systems, logging structures, and time-based organization. The date command offers numerous format options (+%Y for year, +%m for month, +%d for day, etc.). Combined with mkdir -p, you can create complex time-based hierarchies automatically.

Automation: Put these commands in cron jobs or systemd timers for automatic directory creation on schedules.
`
Example 7

Creating Project Directory Structures

#!/bin/bash # create-project.sh - Initialize standard project structure PROJECT_NAME=$1 if [ -z "$PROJECT_NAME" ]; then echo "Usage: $0 project_name" exit 1 fi # Create main project structure mkdir -pv "$PROJECT_NAME"/{src,tests,docs,config,scripts} mkdir -pv "$PROJECT_NAME"/src/{main,lib,utils} mkdir -pv "$PROJECT_NAME"/tests/{unit,integration} mkdir -pv "$PROJECT_NAME"/docs/{api,user,dev} # Create hidden directories mkdir -pv "$PROJECT_NAME"/.{git,vscode} # Create log directory with restricted permissions mkdir -pvm 700 "$PROJECT_NAME"/logs # Create data directories mkdir -pv "$PROJECT_NAME"/data/{raw,processed,output} # Create deployment directories mkdir -pv "$PROJECT_NAME"/deploy/{dev,staging,production} echo "Project structure created successfully!" tree -L 3 "$PROJECT_NAME"
# Running the script: $ ./create-project.sh myapp mkdir: created directory 'myapp' mkdir: created directory 'myapp/src' mkdir: created directory 'myapp/src/main' mkdir: created directory 'myapp/src/lib' mkdir: created directory 'myapp/src/utils' mkdir: created directory 'myapp/tests' mkdir: created directory 'myapp/tests/unit' mkdir: created directory 'myapp/tests/integration' mkdir: created directory 'myapp/docs' mkdir: created directory 'myapp/docs/api' mkdir: created directory 'myapp/docs/user' mkdir: created directory 'myapp/docs/dev' mkdir: created directory 'myapp/config' mkdir: created directory 'myapp/scripts' mkdir: created directory 'myapp/.git' mkdir: created directory 'myapp/.vscode' mkdir: created directory 'myapp/logs' mkdir: created directory 'myapp/data' mkdir: created directory 'myapp/data/raw' mkdir: created directory 'myapp/data/processed' mkdir: created directory 'myapp/data/output' mkdir: created directory 'myapp/deploy' mkdir: created directory 'myapp/deploy/dev' mkdir: created directory 'myapp/deploy/staging' mkdir: created directory 'myapp/deploy/production' Project structure created successfully!

What's Happening:

This script demonstrates real-world usage: creating standardized project structures automatically. It uses mkdir -p extensively to create nested directories, combines it with verbose output for feedback, and sets specific permissions where needed. This approach ensures consistency across projects and saves significant setup time. The script is easily customized for different project types.

Best Practice: Maintain project scaffolding scripts for your common project types. This ensures consistency and includes all necessary directories from the start.
Example 8

Handling Errors and Edge Cases

# Directory already exists: $ mkdir testdir $ mkdir testdir mkdir: cannot create directory 'testdir': File exists # With -p, no error: $ mkdir -p testdir # Silent success # Try to create where you lack permissions: $ mkdir /root/mydir mkdir: cannot create directory '/root/mydir': Permission denied # Create directory with spaces in name: $ mkdir "My Documents" $ ls -l drwxr-xr-x 2 craig staff 64 Nov 7 12:30 My Documents # Or with escaping: $ mkdir My\ Documents $ mkdir 'Project Files' # Multiple paths with error handling: $ mkdir dir1 /root/dir2 dir3 2>/dev/null || echo "Some directories failed" Some directories failed # dir1 and dir3 created, /root/dir2 failed # Check before creating: $ if [ ! -d "newdir" ]; then mkdir newdir echo "Created newdir" else echo "newdir already exists" fi # Safe creation in scripts: $ mkdir -p /tmp/myapp/$USER/cache # Always succeeds

What's Happening:

This example covers error handling scenarios. Without -p, mkdir fails if the directory exists. Permission errors occur when trying to create directories in protected locations. Directory names with spaces must be quoted or escaped. In scripts, use mkdir -p for idempotency, or check for existence first with [ -d directory ]. Error redirection (2>/dev/null) can suppress error messages when desired.

Scripting Warning: In production scripts, don't blindly suppress errors. Check exit codes ($?) and handle failures appropriately.
Example 9

Creating Directories with Context (SELinux)

# On SELinux systems, set security context: $ mkdir -Z httpd_sys_content_t webroot # Or with full context: $ mkdir --context=system_u:object_r:httpd_sys_content_t:s0 website # Check context after creation: $ ls -Z website drwxr-xr-x. craig craig system_u:object_r:httpd_sys_content_t:s0 website # Create with parents and context: $ mkdir -pZ httpd_sys_content_t /var/www/html/app/{public,private} # For web applications: $ sudo mkdir -pvm 755 -Z httpd_sys_content_t /var/www/html/myapp $ ls -ldZ /var/www/html/myapp drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html/myapp # Container-specific contexts: $ mkdir -Z container_file_t /srv/containers/app1

What's Happening:

On systems using SELinux (like RHEL, CentOS, Fedora), the -Z flag sets the security context during directory creation. This is crucial for services like web servers that require specific contexts to access files. The context determines what processes can access the directory. Without proper contexts, services may be denied access even with correct file permissions.

SELinux Systems Only: The -Z flag is only available and necessary on systems with SELinux enabled. Check with: getenforce
Example 10

Advanced: Parallel Directory Creation and Automation

#!/bin/bash # advanced-directory-setup.sh - Enterprise directory provisioning # Configuration BASE_DIR="/srv/application" YEARS=(2023 2024 2025) DEPARTMENTS=("engineering" "marketing" "sales" "hr" "operations") ENVIRONMENTS=("development" "staging" "production") # Function to create directory with logging create_dir() { local dir_path=$1 local permissions=${2:-755} local owner=${3:-} if mkdir -pvm "$permissions" "$dir_path" 2>&1 | tee -a /var/log/directory_setup.log; then [ -n "$owner" ] && chown "$owner" "$dir_path" echo "βœ“ Created: $dir_path (mode: $permissions)" else echo "βœ— Failed: $dir_path" >&2 return 1 fi } # Create multi-dimensional structure echo "Creating enterprise directory structure..." for year in "${YEARS[@]}"; do for dept in "${DEPARTMENTS[@]}"; do for env in "${ENVIRONMENTS[@]}"; do # Main directories create_dir "$BASE_DIR/$dept/$env/$year/data" 755 create_dir "$BASE_DIR/$dept/$env/$year/logs" 750 "root:$dept" create_dir "$BASE_DIR/$dept/$env/$year/config" 700 create_dir "$BASE_DIR/$dept/$env/$year/backups" 700 # Monthly subdirectories for month in {01..12}; do create_dir "$BASE_DIR/$dept/$env/$year/reports/$month" 755 done done done done # Create shared resources echo "Creating shared resource directories..." mkdir -pv "$BASE_DIR"/shared/{templates,scripts,documentation} mkdir -pvm 1777 "$BASE_DIR"/shared/temp # Sticky bit for temp # Create user workspace template echo "Creating user workspace template..." for user in engineering_{1..10}; do mkdir -pv "$BASE_DIR/users/$user"/{workspace,private,shared} mkdir -pvm 700 "$BASE_DIR/users/$user/private" done # Create archive structure echo "Creating archive structure..." mkdir -pv "$BASE_DIR"/archive/$(date +%Y)/{$(date +%m)/{daily,weekly,monthly}} # Summary echo "" echo "Directory creation complete!" echo "Total directories created: $(find "$BASE_DIR" -type d | wc -l)" echo "Structure depth: $(find "$BASE_DIR" -type d -printf '%d\n' | sort -n | tail -1)" echo "Log available at: /var/log/directory_setup.log"

What's Happening:

This comprehensive script demonstrates enterprise-level directory provisioning. It creates multi-dimensional directory structures using loops, sets varying permissions based on purpose, implements logging, includes error handling, and generates summary statistics. The script uses functions for reusability, combines mkdir with chown for ownership assignment, and creates hundreds of directories efficiently. This represents real-world automation for setting up application environments, user workspaces, or departmental structures.

Production Use: Scripts like this are essential for:

Directory Permissions Quick Reference

Octal Symbolic Meaning Use Case
755 rwxr-xr-x Owner: full control; Others: read and execute Standard public directories
750 rwxr-x--- Owner: full; Group: read and execute; Others: none Group-shared directories
700 rwx------ Owner only has full control Private directories (home dirs, sensitive data)
775 rwxrwxr-x Owner and group: full control; Others: read and execute Collaborative team directories
770 rwxrwx--- Owner and group: full control; Others: none Private team projects
1777 rwxrwxrwt Everyone: full access; Sticky bit set Shared temp directories (like /tmp)
2755 rwxr-sr-x Setgid: files inherit group Shared project directories

Directory Permission Notes:

Best Practices & Tips

πŸ’‘ Directory Creation Best Practices

⚠️ Common Mistakes to Avoid

πŸ“ Naming Conventions

Good Directory Names:

Avoid:

Quick Reference: mkdir Options

Option Description Example
-p Create parent directories as needed; no error if exists mkdir -p a/b/c/d
-m MODE Set permissions to MODE during creation mkdir -m 700 private
-v Verbose output (print message for each created directory) mkdir -v newdir
-Z Set SELinux security context (SELinux systems only) mkdir -Z context_t dir
--help Display help message mkdir --help
--version Display version information mkdir --version