Introduction to mkdir
The mkdir (make directory) command is a fundamental utility in Unix/Linux systems for creating directories (folders). It allows users to create single directories, nested directory structures, and set permissions at creation time. Understanding mkdir thoroughly is essential for file system organization, script writing, and system administration.
Key Concepts
- Directory Creation: Creating new folders in the filesystem
- Parent Directories: Creating intermediate directories automatically
- Permissions: Setting access rights at creation time
- Hierarchical Structure: Building nested directory trees
- Error Handling: Dealing with existing directories and permissions
1. Basic Usage
Creating a Single Directory
#!/bin/bash # Create a single directory in current location mkdir projects mkdir documents mkdir downloads # Create directory with absolute path mkdir /home/user/new_folder mkdir ~/backups mkdir /tmp/work_files # Create directory with spaces (use quotes or escape) mkdir "My Documents" mkdir My\ Documents mkdir 'Project Files' # Create multiple directories at once mkdir dir1 dir2 dir3 mkdir projects downloads documents # Create directory and verify mkdir test_dir && ls -ld test_dir # Create directory in parent location mkdir ../shared mkdir ../../global
Creating with Different Paths
#!/bin/bash
# Create in current directory
mkdir ./local_folder
# Create in parent directory
mkdir ../sibling_folder
# Create in home directory
mkdir ~/new_folder
# Create in root (requires sudo usually)
sudo mkdir /opt/myapp
# Create relative to current
mkdir ../../project/src
# Create using variables
BASE_DIR="/opt/app"
mkdir "$BASE_DIR"
mkdir "${BASE_DIR}/logs"
mkdir "${BASE_DIR}/config"
# Create with timestamp
mkdir "backup_$(date +%Y%m%d)"
mkdir "logs_$(date +%Y-%m-%d_%H-%M-%S)"
2. Essential Options
Common Options Reference
#!/bin/bash
# -p: Create parent directories as needed
mkdir -p parent/child/grandchild
# -v: Verbose output (show what's being created)
mkdir -v new_folder
mkdir -v -p a/b/c
# -m: Set permissions (mode) at creation
mkdir -m 755 public_dir
mkdir -m 700 private_dir
mkdir -m 777 shared_dir
# Combine options
mkdir -pv projects/src/main
mkdir -pm 755 apps/web/static
# -p with existing directories (no error)
mkdir -p existing_folder # No error if exists
mkdir existing_folder # Error if exists
# Examples
mkdir -v backup # Create with message
mkdir -p a/b/c/d/e/f # Create nested directories
mkdir -m 700 ~/private # Private directory
mkdir -pv /tmp/test/{sub1,sub2} # Create multiple subdirs
Practical Option Combinations
#!/bin/bash
# Create full path with permissions
create_path() {
local path="$1"
local mode="${2:-755}"
mkdir -p -m "$mode" "$path"
echo "Created: $path with mode $mode"
}
# Create project structure
create_project() {
local name="$1"
mkdir -pv "$name"/{src,bin,docs,tests}
mkdir -pv "$name"/src/{main,test}
mkdir -pv "$name"/docs/{api,user}
echo "Project structure created for: $name"
}
# Safe directory creation
safe_mkdir() {
local dir="$1"
if [ -e "$dir" ]; then
echo "Error: $dir already exists" >&2
return 1
fi
mkdir "$dir"
}
# Create with timestamp and permissions
create_backup_dir() {
local base="${1:-./backups}"
local mode="${2:-750}"
local date=$(date +%Y%m%d_%H%M%S)
local dir="$base/$date"
mkdir -p -m "$mode" "$dir"
echo "$dir"
}
# Usage
create_path "/opt/myapp/data" 750
create_project "myapp"
safe_mkdir "unique_dir"
backup_dir=$(create_backup_dir "/backups" 700)
3. Creating Nested Directories
Using -p for Parent Directories
#!/bin/bash
# Basic nested creation
mkdir -p parent/child/grandchild
# Multiple levels
mkdir -p a/b/c/d/e/f/g
# Create with complex paths
mkdir -p /opt/app/{config,logs,data}
mkdir -p project/src/{main,test}/java
mkdir -p ~/work/{2024/{q1,q2,q3,q4},archive}
# Create from variable
BASE="/opt/myapp"
mkdir -p "$BASE"/{bin,conf,logs,data/{db,cache}}
# Create with brace expansion
mkdir -p src/{main,test}/{java,resources}
mkdir -p project/{lib,bin,doc}/{html,pdf}
# Nested with permissions
mkdir -pm 755 app/{web/{static,templates},api}
# Create and cd into directory
mkcd() {
mkdir -p "$1" && cd "$1"
}
# Usage
mkcd /tmp/test/nested/dir
Complex Directory Structures
#!/bin/bash
# Create project skeleton
create_java_project() {
local name="$1"
mkdir -p "$name"/src/{main,test}/{java,resources}
mkdir -p "$name"/src/main/java/com/example
mkdir -p "$name"/src/test/java/com/example
mkdir -p "$name"/{target,lib,docs}
echo "Java project structure created for: $name"
}
# Create web application structure
create_webapp() {
local name="$1"
mkdir -p "$name"/{public,src,dist}
mkdir -p "$name"/public/{css,js,images}
mkdir -p "$name"/src/{components,utils,styles}
mkdir -p "$name"/src/components/{common,features}
echo "Web app structure created for: $name"
}
# Create data science project
create_ds_project() {
local name="$1"
mkdir -p "$name"/{data/{raw,processed,external},notebooks,src,models,outputs}
mkdir -p "$name"/src/{data,features,models,visualization}
mkdir -p "$name"/configs
echo "Data science project created for: $name"
}
# Create multi-module project
create_multi_module() {
local root="$1"
shift
local modules=("$@")
mkdir -p "$root"/{shared,common}
for module in "${modules[@]}"; do
mkdir -p "$root/$module"/{src,test,resources}
done
}
# Usage
create_java_project "myapp"
create_webapp "frontend"
create_ds_project "analysis"
create_multi_module "project" "core" "web" "api"
4. Setting Permissions at Creation
Using -m Option
#!/bin/bash
# Basic permission settings
mkdir -m 755 public # rwxr-xr-x
mkdir -m 700 private # rwx------
mkdir -m 777 shared # rwxrwxrwx
mkdir -m 644 readonly # rw-r--r-- (unusual for dirs)
# Octal permissions
mkdir -m 755 dir1
mkdir -m 750 dir2
mkdir -m 770 dir3
mkdir -m 700 dir4
mkdir -m 555 dir5 # Read-only directory
# Symbolic permissions
mkdir -m u=rwx,g=rx,o=rx dir6
mkdir -m u=rwx,g=,o= dir7 # Private
mkdir -m a=rwx dir8 # All permissions
mkdir -m u=rwx,g=rwxs,o= dir9 # With setgid
# Combining with -p
mkdir -pm 755 a/b/c/d
mkdir -pm 700 ~/private/{docs,config}
# Check permissions
ls -ld dir1 dir2 dir3
# Create with umask consideration
(umask 022 && mkdir dir10) # Creates with 755
(umask 077 && mkdir dir11) # Creates with 700
Advanced Permission Patterns
#!/bin/bash
# Create shared directory with sticky bit
mkdir -m 1777 shared # /tmp style directory
# Create with setgid (new files inherit group)
mkdir -m 2755 project_group # Setgid + rwxr-xr-x
# Create with setuid (rare for directories)
mkdir -m 4755 special_dir
# Create restricted directory for web server
mkdir -m 755 public_html
mkdir -m 700 private_data
# Create directories for different purposes
create_secure_dir() {
local dir="$1"
mkdir -m 700 "$dir"
}
create_shared_dir() {
local dir="$1"
mkdir -m 775 "$dir"
chown :www-data "$dir" 2>/dev/null || true
}
create_temp_dir() {
local dir="$1"
mkdir -m 1777 "$dir"
}
# Create with specific user/group
create_owned_dir() {
local dir="$1"
local user="$2"
local group="$3"
local mode="${4:-755}"
mkdir -m "$mode" "$dir"
chown "$user:$group" "$dir"
}
# Usage
create_secure_dir "secrets"
create_shared_dir "uploads"
create_temp_dir "/tmp/custom"
create_owned_dir "/opt/app" "www-data" "www-data" 750
5. Error Handling
Common Error Scenarios
#!/bin/bash # Error: Directory already exists mkdir existing_dir mkdir: cannot create directory ‘existing_dir’: File exists # Solution: Use -p to suppress error mkdir -p existing_dir # Error: No such file or directory (parent missing) mkdir parent/child mkdir: cannot create directory ‘parent/child’: No such file or directory # Solution: Use -p to create parents mkdir -p parent/child # Error: Permission denied mkdir /root/test mkdir: cannot create directory ‘/root/test’: Permission denied # Solution: Use sudo sudo mkdir /root/test # Error: Read-only filesystem mkdir /media/cdrom/test mkdir: cannot create directory ‘/media/cdrom/test’: Read-only file system # Solution: Can't create on read-only filesystem # Error: Invalid characters mkdir "invalid/" mkdir: cannot create directory ‘invalid/’: Invalid argument # Solution: Remove invalid characters mkdir "valid"
Robust Error Handling
#!/bin/bash
# Safe directory creation with error checking
safe_mkdir() {
local dir="$1"
local mode="${2:-}"
# Check if path already exists
if [ -e "$dir" ]; then
if [ -d "$dir" ]; then
echo "Warning: $dir already exists and is a directory" >&2
return 0
else
echo "Error: $dir exists but is not a directory" >&2
return 1
fi
fi
# Create directory with optional mode
if [ -n "$mode" ]; then
mkdir -m "$mode" "$dir" 2>/dev/null
else
mkdir "$dir" 2>/dev/null
fi
local result=$?
if [ $result -eq 0 ]; then
echo "Created: $dir"
else
echo "Error: Failed to create $dir" >&2
fi
return $result
}
# Create with retry logic
mkdir_with_retry() {
local dir="$1"
local max_attempts="${2:-3}"
local attempt=1
while [ $attempt -le $max_attempts ]; do
if mkdir "$dir" 2>/dev/null; then
echo "Created $dir on attempt $attempt"
return 0
fi
echo "Attempt $attempt failed, retrying..." >&2
sleep $((attempt * 2))
attempt=$((attempt + 1))
done
echo "Failed to create $dir after $max_attempts attempts" >&2
return 1
}
# Create with parent verification
mkdir_verify() {
local path="$1"
local required_parents="${2:-}"
# Check parent directory exists if required
if [ -n "$required_parents" ]; then
local parent=$(dirname "$path")
if [ ! -d "$parent" ]; then
echo "Error: Parent directory $parent does not exist" >&2
return 1
fi
fi
mkdir -p "$path"
}
# Create with logging
log_mkdir() {
local dir="$1"
local log_file="${2:-/var/log/mkdir.log}"
if mkdir -p "$dir" 2>>"$log_file"; then
echo "$(date): Created $dir" >> "$log_file"
return 0
else
echo "$(date): Failed to create $dir" >> "$log_file"
return 1
fi
}
# Usage
safe_mkdir "/tmp/test" 755
mkdir_with_retry "/tmp/unique_dir" 5
mkdir_verify "/opt/app/data" "required"
log_mkdir "/var/log/myapp" "/var/log/myapp_mkdir.log"
6. Advanced Directory Creation
Using Brace Expansion
#!/bin/bash
# Basic brace expansion
mkdir {dir1,dir2,dir3}
mkdir {a,b,c}/{x,y,z}
mkdir project/{src,test,docs}
mkdir -p data/{2024/{01,02,03},archive}
# Nested brace expansion
mkdir -p src/{main,test}/{java,resources}/{com/example}
mkdir -p {prod,dev,test}/{config,logs,data}
mkdir -p project/{lib,bin,share}/{linux,windows,macos}
# Combining with ranges
mkdir {1..5} # Creates 1,2,3,4,5
mkdir {a..e} # Creates a,b,c,d,e
mkdir {01..12} # Zero-padded numbers
mkdir q{1..4} # q1,q2,q3,q4
# More complex combinations
mkdir -p 2024/{Q{1..4}/{month{1..3}}}
mkdir -p {backend,frontend}/src/{components,utils,pages}
mkdir -p data/{raw,processed}/{train,test,validate}/{images,labels}
# Practical example: Create test data structure
create_test_data() {
mkdir -p test_data/{batch{1..5}/{positive,negative,neutral}}
mkdir -p test_data/{validation,training,testing}/{set{1..3}}
}
# Create multiple projects
create_projects() {
local projects=("web" "api" "worker" "scheduler")
local environments=("dev" "staging" "prod")
for project in "${projects[@]}"; do
for env in "${environments[@]}"; do
mkdir -p "$project/$env"/{config,logs,data}
done
done
}
Programmatic Directory Creation
#!/bin/bash
# Create directories from array
dirs=(
"project/src/main"
"project/src/test"
"project/docs/api"
"project/docs/user"
"project/config/dev"
"project/config/prod"
)
for dir in "${dirs[@]}"; do
mkdir -p "$dir"
done
# Create from file list
while IFS= read -r dir; do
mkdir -p "$dir"
done < directories.txt
# Create with counter
for i in {1..10}; do
mkdir -p "batch_$i"/{input,output,logs}
done
# Create based on date
for month in {01..12}; do
mkdir -p "logs/2024/$month"/{01..31}
done
# Create with conditions
for i in {1..100}; do
if [ $((i % 2)) -eq 0 ]; then
mkdir "even_dir_$i"
else
mkdir "odd_dir_$i"
fi
done
# Create based on file content
create_from_config() {
local config="$1"
while IFS=':' read -r name mode; do
mkdir -m "$mode" "$name"
done < "$config"
}
# Usage example config.txt:
# public:755
# private:700
# shared:775
7. Script Examples
Directory Creation Functions
#!/bin/bash
# Comprehensive directory creation library
# Create directory if not exists
ensure_dir() {
local dir="$1"
local mode="${2:-755}"
if [ ! -d "$dir" ]; then
mkdir -p -m "$mode" "$dir"
echo "Created directory: $dir"
else
echo "Directory already exists: $dir"
fi
}
# Create temporary directory
make_temp_dir() {
local prefix="${1:-tmp}"
local dir
dir=$(mktemp -d "/tmp/${prefix}.XXXXXX")
echo "$dir"
}
# Create timestamped directory
make_timestamp_dir() {
local base="${1:-.}"
local name="${2:-backup}"
local timestamp=$(date +%Y%m%d_%H%M%S)
local dir="$base/${name}_$timestamp"
mkdir -p "$dir"
echo "$dir"
}
# Create directory with all subdirectories
make_full_path() {
local path="$1"
local mode="${2:-755}"
IFS='/' read -ra parts <<< "$path"
local current=""
for part in "${parts[@]}"; do
if [ -n "$part" ]; then
current="$current/$part"
if [ ! -d "$current" ]; then
mkdir -m "$mode" "$current"
echo "Created: $current"
fi
fi
done
}
# Create versioned directories
make_versioned_dirs() {
local base="$1"
local versions=("v1.0" "v1.1" "v2.0" "v2.1")
for version in "${versions[@]}"; do
mkdir -p "$base/$version"/{bin,lib,conf}
done
}
# Create directory tree with metadata
make_tree_with_metadata() {
local root="$1"
local metadata_file="$root/.metadata"
mkdir -p "$root"
echo "Created: $(date)" > "$metadata_file"
echo "User: $USER" >> "$metadata_file"
# Create subdirectories
mkdir -p "$root"/{data,logs,temp}
# Add metadata to subdirs
for dir in data logs temp; do
echo "Parent: $root" > "$root/$dir/.metadata"
done
}
Installation Script Example
#!/bin/bash
# Application installation script with directory creation
APP_NAME="myapp"
INSTALL_DIR="/opt/$APP_NAME"
CONFIG_DIR="/etc/$APP_NAME"
LOG_DIR="/var/log/$APP_NAME"
DATA_DIR="/var/lib/$APP_NAME"
RUN_DIR="/var/run/$APP_NAME"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
log() {
echo -e "${GREEN}[INFO]${NC} $1"
}
warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1"
exit 1
}
create_directories() {
log "Creating application directories..."
# Main application directory
ensure_dir "$INSTALL_DIR" 755
ensure_dir "$INSTALL_DIR/bin" 755
ensure_dir "$INSTALL_DIR/lib" 755
ensure_dir "$INSTALL_DIR/plugins" 755
# Configuration directory
ensure_dir "$CONFIG_DIR" 750
ensure_dir "$CONFIG_DIR/default" 755
ensure_dir "$CONFIG_DIR/custom" 750
# Log directory
ensure_dir "$LOG_DIR" 750
ensure_dir "$LOG_DIR/archive" 750
# Data directory
ensure_dir "$DATA_DIR" 750
ensure_dir "$DATA_DIR/db" 750
ensure_dir "$DATA_DIR/cache" 750
ensure_dir "$DATA_DIR/temp" 750
# Run directory (for PID files)
ensure_dir "$RUN_DIR" 755
log "Directory structure created successfully"
}
ensure_dir() {
local dir="$1"
local mode="$2"
if [ ! -d "$dir" ]; then
mkdir -p -m "$mode" "$dir" || error "Failed to create $dir"
log " Created: $dir ($mode)"
else
warn " Directory already exists: $dir"
fi
}
set_permissions() {
log "Setting directory permissions..."
chown -R root:root "$INSTALL_DIR"
chown -R root:adm "$CONFIG_DIR"
chown -R root:adm "$LOG_DIR"
chown -R $APP_USER:$APP_GROUP "$DATA_DIR" 2>/dev/null || warn "User $APP_USER not found"
log "Permissions set successfully"
}
check_prerequisites() {
# Check if running as root
if [ "$EUID" -ne 0 ]; then
error "This script must be run as root"
fi
# Check available disk space
local required_space=1000000 # 1GB in KB
local available_space=$(df "$INSTALL_DIR" | awk 'NR==2 {print $4}')
if [ "$available_space" -lt "$required_space" ]; then
error "Insufficient disk space. Need at least 1GB"
fi
}
main() {
log "Starting installation of $APP_NAME..."
check_prerequisites
create_directories
set_permissions
log "Installation completed successfully"
}
# Run main function
main
8. Integration with Other Commands
Using with find
#!/bin/bash
# Create directories for each file type
find . -type f -name "*.txt" | while read file; do
dir=$(dirname "$file")/txt_backup
mkdir -p "$dir"
cp "$file" "$dir/"
done
# Create directory structure matching another
find source_dir -type d | while read dir; do
target="dest_dir/${dir#source_dir/}"
mkdir -p "$target"
done
# Create directories for each extension
find . -type f | sed -n 's/.*\.//p' | sort -u | while read ext; do
mkdir -p "by_extension/$ext"
done
# Create directories based on file dates
find . -type f -printf '%TY-%Tm\n' | sort -u | while read date; do
mkdir -p "by_date/$date"
done
Using with xargs
#!/bin/bash
# Create directories from list
echo "dir1 dir2 dir3" | xargs mkdir
# Create from file
cat directories.txt | xargs mkdir -p
# Parallel directory creation
seq 1 100 | xargs -P 10 -I {} mkdir "dir_{}"
# Create with options
find . -name "*.tmp" | sed 's/\.tmp$//' | xargs -I {} mkdir -p "{}_backup"
# Safe xargs with null delimiter
find . -type d -print0 | xargs -0 -I {} mkdir "copy_{}"
Using with rsync
#!/bin/bash # Create destination directory structure rsync -av --files-from=<(find source -type f) source/ dest/ # Sync directory structure only rsync -av -f"+ */" -f"- *" source/ dest/ # Create directories before rsync ssh user@host "mkdir -p /remote/path/subdirs" # Rsync with directory creation rsync -av --rsync-path="mkdir -p /dest && rsync" source/ user@host:/dest/
9. Special Use Cases
Creating Directories with Special Characters
#!/bin/bash # Spaces mkdir "My Documents" mkdir My\ Documents mkdir 'Project Files 2024' # Special characters mkdir "project#123" mkdir "file&name" mkdir "[email protected]" mkdir "path+plus" # Unicode/UTF-8 mkdir "数据备份" mkdir "проекты" mkdir "📁documents" # Starting with dash (use -- to stop option parsing) mkdir -- -directory mkdir -- --double-dash # With colons mkdir "name:with:colons" # With brackets mkdir "project[2024]" mkdir "file{version}" # Safe handling in scripts name="My Document" mkdir "$name" mkdir "${name// /_}" # Replace spaces with underscores
Creating Temporary Directories
#!/bin/bash
# Using mktemp
temp_dir=$(mktemp -d)
echo "Temporary directory: $temp_dir"
# Use directory
# Clean up
rm -rf "$temp_dir"
# Custom prefix
temp_dir=$(mktemp -d /tmp/myapp.XXXXXX)
temp_dir=$(mktemp -d --tmpdir=/var/tmp myapp.XXXX)
# Trap cleanup
cleanup() {
if [ -n "$temp_dir" ] && [ -d "$temp_dir" ]; then
rm -rf "$temp_dir"
echo "Cleaned up $temp_dir"
fi
}
trap cleanup EXIT
temp_dir=$(mktemp -d)
cd "$temp_dir" || exit 1
# Work in temp directory
mkdir {input,output,logs}
echo "Working in $temp_dir"
# Script will automatically clean up on exit
# Multiple temp directories
build_dir=$(mktemp -d)
cache_dir=$(mktemp -d)
# Create with specific permissions
secure_temp() {
local dir
dir=$(mktemp -d)
chmod 700 "$dir"
echo "$dir"
}
Creating Directories for Mount Points
#!/bin/bash
# Create mount point
sudo mkdir -p /mnt/backup
sudo mount /dev/sdb1 /mnt/backup
# Create multiple mount points
for i in {1..5}; do
sudo mkdir -p "/mnt/disk$i"
done
# Create with specific permissions for mount
create_mount_point() {
local point="$1"
local user="${2:-$USER}"
sudo mkdir -p "$point"
sudo chown "$user" "$point"
sudo chmod 755 "$point"
}
# Create loop device mount point
create_loop_mount() {
local image="$1"
local point="/mnt/loop_$(basename "$image")"
mkdir -p "$point"
sudo mount -o loop "$image" "$point"
echo "Mounted $image at $point"
}
# Usage
create_mount_point "/media/extradrive" "$USER"
10. Performance Considerations
Bulk Directory Creation
#!/bin/bash
# Efficient bulk creation
time {
for i in {1..1000}; do
mkdir "dir_$i"
done
}
# Using xargs (faster for many directories)
time {
seq 1 1000 | xargs -P 4 -I {} mkdir "dir_{}"
}
# Using parallel (if installed)
time {
seq 1 1000 | parallel mkdir "dir_{}"
}
# Create directory tree efficiently
create_tree() {
local depth="${1:-3}"
local breadth="${2:-5}"
# Use brace expansion for efficient creation
local dirs=""
for i in $(seq 1 $depth); do
dirs="$dirs/level$i"
done
mkdir -p "root$dirs"
# Create multiple leaf directories
for i in $(seq 1 $breadth); do
mkdir -p "root$dirs/branch$i"
done
}
# Benchmark different methods
benchmark_mkdir() {
local count=1000
echo "Method 1: Sequential"
time {
for i in $(seq 1 $count); do
mkdir "test1_$i" 2>/dev/null
done
rm -rf test1_*
}
echo "Method 2: xargs"
time {
seq 1 $count | xargs -I {} mkdir "test2_{}" 2>/dev/null
rm -rf test2_*
}
echo "Method 3: Brace expansion"
time {
eval mkdir test3_{1..$count} 2>/dev/null
rm -rf test3_*
}
}
Filesystem Considerations
#!/bin/bash
# Check filesystem type before creating
check_fs_type() {
local dir="$1"
local fs_type=$(df -T "$dir" | awk 'NR==2 {print $2}')
echo "Filesystem type: $fs_type"
}
# Create with consideration for filesystem limits
safe_mkdir_with_limits() {
local path="$1"
local max_path=$(getconf PATH_MAX /)
local max_name=$(getconf NAME_MAX /)
# Check path length
if [ ${#path} -gt $max_path ]; then
echo "Error: Path too long (max $max_path)" >&2
return 1
fi
# Check component names
IFS='/' read -ra parts <<< "$path"
for part in "${parts[@]}"; do
if [ ${#part} -gt $max_name ]; then
echo "Error: Component '$part' too long (max $max_name)" >&2
return 1
fi
done
mkdir -p "$path"
}
# Create directories on specific filesystem
create_on_fs() {
local base="$1"
local fs="$2"
shift 2
# Check if base is on correct filesystem
local base_fs=$(df -T "$base" | awk 'NR==2 {print $2}')
if [ "$base_fs" != "$fs" ]; then
echo "Error: $base is on $base_fs, not $fs" >&2
return 1
fi
for dir in "$@"; do
mkdir -p "$base/$dir"
done
}
11. Best Practices and Tips
Shell Configuration
# ~/.bashrc additions
# Aliases for common mkdir operations
alias mkdir='mkdir -p' # Always create parents
alias mkv='mkdir -v' # Verbose
alias mkdir='mkdir -v' # Verbose by default
alias mkd='mkdir -p' # Create with parents
alias mk='mkdir -p' # Short version
# Function to create and cd
mkcd() {
mkdir -p "$1" && cd "$1"
}
# Function to create multiple directories
mkd() {
for dir in "$@"; do
mkdir -p "$dir"
done
}
# Function to create with timestamp
mkt() {
local base="${1:-.}"
local name="${2:-dir}"
local timestamp=$(date +%Y%m%d_%H%M%S)
mkdir -p "$base/${name}_$timestamp"
}
# Function to create with permissions
mkdm() {
local mode="$1"
local dir="$2"
mkdir -m "$mode" -p "$dir"
}
# Function to create project structure
mkproj() {
local name="$1"
mkdir -p "$name"/{src,bin,docs,test}
mkdir -p "$name"/src/{main,test}
echo "Project $name created"
}
# Tab completion for mkcd
_mkcd_complete() {
COMPREPLY=($(compgen -d -- "${COMP_WORDS[COMP_CWORD]}"))
}
complete -F _mkcd_complete mkcd
Security Best Practices
#!/bin/bash
# 1. Always check before creating in sensitive locations
safe_mkdir_sensitive() {
local dir="$1"
# Don't create in root
if [ "$dir" = "/" ] || [ "$dir" = "/etc" ] || [ "$dir" = "/bin" ]; then
echo "Error: Refusing to create directory in system location" >&2
return 1
fi
mkdir -p "$dir"
}
# 2. Set secure permissions by default
umask 077
mkdir private_dir
# 3. Avoid race conditions (CWE-367)
if mkdir "$dir" 2>/dev/null; then
echo "Successfully created $dir"
else
echo "Directory $dir already exists or cannot be created"
fi
# 4. Check symlinks before creating
safe_mkdir_no_symlink() {
local dir="$1"
if [ -L "$dir" ]; then
echo "Error: $dir is a symlink" >&2
return 1
fi
mkdir -p "$dir"
}
# 5. Create with least privileges
drop_privileges() {
local user="${1:-nobody}"
local dir="$2"
if id "$user" >/dev/null 2>&1; then
sudo -u "$user" mkdir -p "$dir"
else
echo "User $user does not exist" >&2
return 1
fi
}
# 6. Validate directory names
validate_dirname() {
local name="$1"
# Check for invalid characters
if [[ "$name" =~ [/] ]]; then
echo "Error: Directory name contains slash" >&2
return 1
fi
# Check length
if [ ${#name} -gt 255 ]; then
echo "Error: Directory name too long" >&2
return 1
fi
return 0
}
# 7. Create with audit logging
audit_mkdir() {
local dir="$1"
local user="$USER"
local pid=$$
if mkdir -p "$dir"; then
logger -p user.info "mkdir: $user($pid) created $dir"
else
logger -p user.err "mkdir: $user($pid) failed to create $dir"
fi
}
Tips for Scripts
#!/bin/bash
# 1. Always use -p in scripts
mkdir -p /var/log/myapp
# 2. Check return codes
if ! mkdir -p "$dir"; then
echo "Failed to create $dir" >&2
exit 1
fi
# 3. Use variables for paths
LOG_DIR="/var/log/myapp"
mkdir -p "$LOG_DIR"
# 4. Create with proper permissions
mkdir -m 755 -p "$LOG_DIR"
# 5. Handle existing directories gracefully
mkdir -p "$dir" 2>/dev/null || true
# 6. Use trap for temporary directories
cleanup() {
rm -rf "$TMPDIR"
}
TMPDIR=$(mktemp -d)
trap cleanup EXIT
# 7. Create directory structure from config
while IFS=: read dir mode owner group; do
mkdir -p "$dir"
chmod "$mode" "$dir"
chown "$owner:$group" "$dir" 2>/dev/null
done < directories.cfg
# 8. Test before creating
if [ -w "$(dirname "$dir")" ]; then
mkdir -p "$dir"
else
echo "Parent directory not writable" >&2
exit 1
fi
# 9. Create multiple directories atomically
create_atomic() {
local dirs=("$@")
for dir in "${dirs[@]}"; do
if ! mkdir -p "$dir"; then
# Rollback
for d in "${dirs[@]}"; do
[ -d "$d" ] && rmdir "$d" 2>/dev/null
done
return 1
fi
done
return 0
}
# 10. Use readlink to resolve paths
abs_dir=$(readlink -f "$rel_dir")
mkdir -p "$abs_dir"
12. Troubleshooting
Common Issues and Solutions
#!/bin/bash
# Issue: Permission denied
# Solution: Check permissions and use sudo if needed
ls -ld "$(dirname "$dir")"
sudo mkdir -p "$dir"
# Issue: No space left on device
# Solution: Check disk space
df -h "$dir"
du -sh "$dir" 2>/dev/null
# Issue: Read-only filesystem
# Solution: Check mount options
mount | grep "$(df "$dir" | awk 'NR==2 {print $1}')"
# Issue: Invalid argument (bad characters)
# Solution: Sanitize filename
sanitize_name() {
echo "$1" | tr -cd '[:alnum:] ._-'
}
mkdir "$(sanitize_name "$raw_name")"
# Issue: File exists but not a directory
# Solution: Remove or rename file
if [ -e "$dir" ] && [ ! -d "$dir" ]; then
mv "$dir" "$dir.bak"
mkdir "$dir"
fi
# Issue: Path too long
# Solution: Use shorter names or reorganize
max_path=$(getconf PATH_MAX "$dir")
echo "Max path length: $max_path"
# Issue: Permission denied in script but works manually
# Solution: Check environment and umask
echo "umask: $(umask)"
echo "PATH: $PATH"
echo "User: $(whoami)"
# Diagnostic function
diagnose_mkdir() {
local dir="$1"
echo "=== Diagnosing mkdir for: $dir ==="
echo "Current user: $(whoami)"
echo "Current directory: $(pwd)"
echo "Parent directory: $(dirname "$dir")"
if [ -e "$(dirname "$dir")" ]; then
ls -ld "$(dirname "$dir")"
df -h "$(dirname "$dir")"
else
echo "Parent directory does not exist"
fi
if [ -e "$dir" ]; then
echo "Target already exists:"
ls -ld "$dir"
fi
echo "Filesystem type: $(df -T "$(dirname "$dir")" 2>/dev/null | awk 'NR==2 {print $2}')"
echo "Free space: $(df -h "$(dirname "$dir")" 2>/dev/null | awk 'NR==2 {print $4}')"
}
Debugging Techniques
#!/bin/bash
# Enable debug mode
set -x
mkdir -p test/dir
set +x
# Verbose output
mkdir -v parent/child
# Dry run (simulate)
mkdir -pv --dry-run a/b/c
# Trace system calls
strace -e trace=file mkdir testdir 2>&1 | grep mkdir
# Check with shellcheck
# shellcheck disable=SC2164
cd "$(mktemp -d)" || exit 1
# Log all mkdir operations
mkdir() {
echo "$(date): mkdir $*" >> /tmp/mkdir.log
command mkdir "$@"
}
# Debug with bash debugger
trap 'echo "About to create: $BASH_COMMAND"' DEBUG
mkdir test
trap - DEBUG
# Profile directory creation
time mkdir -p a/b/c/d/e/f
# Check filesystem limits
ulimit -a
getconf PATH_MAX .
getconf NAME_MAX .
Conclusion
The mkdir command is fundamental to filesystem organization and mastering it involves understanding:
Key Takeaways
- Basic Operations: Creating single or multiple directories
- Parent Creation:
-pfor creating intermediate directories - Permissions:
-mfor setting modes at creation - Verbose Mode:
-vfor feedback - Error Handling: Dealing with existing directories and permissions
- Brace Expansion: Efficiently creating multiple directories
- Integration: Working with find, xargs, and other commands
- Scripting: Robust patterns for scripts
- Security: Proper permissions and validation
- Performance: Efficient bulk creation techniques
Best Practices Summary
- Use
-pin scripts to ensure parent directories exist - Set explicit permissions with
-mfor security - Check return codes in scripts
- Validate directory names before creation
- Use variables for paths
- Create temporary directories with
mktemp - Handle errors gracefully
- Use brace expansion for multiple directories
- Consider umask settings
- Test with
-vduring development
The mkdir command may seem simple, but its proper use is crucial for system administration, script writing, and maintaining organized file systems.