Generate UUID in Bash
uuidgen is built into Linux and macOS — zero dependencies, reads directly from the kernel entropy pool. Also available via /proc/sys/kernel/random/uuid on Linux.
Quick Reference
| Method | Platform | Version | Notes |
|---|---|---|---|
| uuidgen | Linux + macOS | v4 (Linux) / v1 (macOS default) | Most portable — use -r flag for random |
| /proc/sys/kernel/random/uuid | Linux only | v4 | Kernel-generated, always random |
| python3 -c "import uuid..." | Any | v4 | Fallback when uuidgen unavailable |
Primary Implementation
#!/usr/bin/env bash
# ── Method 1: uuidgen (Linux + macOS) ──────────────────────────
# On Linux: generates v4 (random) by default
# On macOS: generates v1 by default — use -r flag for random v4
uuidgen # Linux: v4 random
uuidgen -r # macOS: force random v4
uuidgen | tr '[:upper:]' '[:lower:]' # lowercase output
# ── Method 2: /proc virtual file (Linux only) ──────────────────
# The kernel generates a fresh v4 UUID on every read
cat /proc/sys/kernel/random/uuid
# ── Method 3: Python fallback (any platform) ──────────────────
python3 -c "import uuid; print(uuid.uuid4())"
# ── Assign to a variable ──────────────────────────────────────
UUID=$(uuidgen | tr '[:upper:]' '[:lower:]')
echo "Generated: $UUID"
# ── Generate multiple UUIDs ───────────────────────────────────
for i in {1..5}; do
uuidgen | tr '[:upper:]' '[:lower:]'
done
# ── Validate a UUID with regex ────────────────────────────────
validate_uuid() {
local uuid="$1"
if [[ "$uuid" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$ ]]; then
echo "Valid UUID"
else
echo "Invalid UUID"
fi
}
validate_uuid "$(uuidgen | tr '[:upper:]' '[:lower:]')"
All Approaches
Cross-platform portable function
#!/usr/bin/env bash
# Portable UUID v4 generator — works on Linux and macOS
generate_uuid() {
if command -v uuidgen &>/dev/null; then
# macOS uses -r for random; Linux ignores it
uuidgen -r 2>/dev/null || uuidgen | tr '[:upper:]' '[:lower:]'
elif [[ -r /proc/sys/kernel/random/uuid ]]; then
cat /proc/sys/kernel/random/uuid
elif command -v python3 &>/dev/null; then
python3 -c "import uuid; print(uuid.uuid4())"
else
echo "Error: no UUID generator found" >&2
return 1
fi
}
UUID=$(generate_uuid)
echo "$UUID"
No hyphens / uppercase variants
#!/usr/bin/env bash # Lowercase with hyphens (standard) UUID_LOWER=$(uuidgen | tr '[:upper:]' '[:lower:]') echo "$UUID_LOWER" # → f47ac10b-58cc-4372-a567-0e02b2c3d479 # No hyphens (32 hex chars) UUID_HEX=$(uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]') echo "$UUID_HEX" # → f47ac10b58cc4372a5670e02b2c3d479 # Uppercase (default on macOS) UUID_UPPER=$(uuidgen) echo "$UUID_UPPER" # → F47AC10B-58CC-4372-A567-0E02B2C3D479
Real-World Use Cases
1. Deployment script — unique release ID
#!/usr/bin/env bash
set -euo pipefail
RELEASE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
DEPLOY_TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
echo "Starting deployment: $RELEASE_ID at $DEPLOY_TIME"
# Tag the Docker image with the release UUID
docker build -t "myapp:$RELEASE_ID" .
docker push "myapp:$RELEASE_ID"
# Write release metadata
cat > release.json <<EOF
{
"releaseId": "$RELEASE_ID",
"deployedAt": "$DEPLOY_TIME",
"image": "myapp:$RELEASE_ID"
}
EOF
echo "Deployment $RELEASE_ID complete"
2. Log file with unique session ID
#!/usr/bin/env bash
SESSION_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
LOG_FILE="/var/log/myapp/session-${SESSION_ID}.log"
log() {
echo "[$(date -u +"%Y-%m-%dT%H:%M:%SZ")] [$SESSION_ID] $*" | tee -a "$LOG_FILE"
}
log "Session started"
log "Running backup..."
# ... backup logic ...
log "Backup complete"
3. Temp directory with UUID name
#!/usr/bin/env bash # Create a unique temp directory — no collision risk WORK_DIR="/tmp/job-$(uuidgen | tr '[:upper:]' '[:lower:]')" mkdir -p "$WORK_DIR" # Ensure cleanup on exit trap "rm -rf '$WORK_DIR'" EXIT echo "Working in: $WORK_DIR" # ... do work in $WORK_DIR ... echo "Done — temp dir will be cleaned up"
Common Mistakes
Using uuidgen on macOS without -r
On macOS, uuidgen generates a v1 UUID (timestamp + MAC address) by default. Use uuidgen -r to force a random v4 UUID. On Linux, uuidgen generates v4 by default.
Using $RANDOM for unique IDs
$RANDOM only provides 15 bits of entropy (0—32767). It is not CSPRNG-backed and has a very high collision probability. Never use it for unique identifiers.
Not quoting UUID variables in shell scripts
Always quote UUID variables: "$UUID" not $UUID. While UUIDs don't contain spaces, it's a good habit and prevents issues if the variable is ever empty.
How It Works
uuidgen on Linux reads from /dev/urandom (the kernel CSPRNG) to generate 16 random bytes, then formats them as a UUID v4 string.
/proc/sys/kernel/random/uuid is a virtual file — the Linux kernel generates a fresh v4 UUID on every read() call. It's slightly faster than spawning uuidgen as a subprocess.
On macOS, uuidgen is part of the system and uses SecRandomCopyBytes for the -r (random) mode.
Output Formats
uuidgen (Linux default)
F47AC10B-58CC-4372-A567-0E02B2C3D479
lowercase
f47ac10b-58cc-4372-a567-0e02b2c3d479
no hyphens
f47ac10b58cc4372a5670e02b2c3d479
Best Practices
Use uuidgen -r on macOS to guarantee a random v4 UUID.
Pipe through tr '[:upper:]' '[:lower:]' for consistent lowercase output.
Write a portable generate_uuid() function that falls back gracefully across platforms.
Performance
Each uuidgen call spawns a subprocess — fast for occasional use but not suitable for generating thousands of UUIDs in a loop. For bulk generation in scripts, use Python or a compiled tool.
Reading /proc/sys/kernel/random/uuid avoids subprocess overhead on Linux — it's a direct kernel call.
Installation
# macOS — built-in, no install needed
# Debian/Ubuntu
apt install uuid-runtime
# RHEL/CentOS
yum install util-linux
On most modern Linux distros, uuidgen is pre-installed as part of util-linux.
Security
Entropy source: /dev/urandom on Linux (kernel CSPRNG), SecRandomCopyBytes on macOS. Cryptographically secure.
Suitable for deployment IDs, session tokens in scripts, and unique file/directory names. Never use $RANDOM or date +%s for security-sensitive IDs.