How to Create a Bash Password Generator

How to Create a Bash Password Generator

How to Create a Bash Password Generator

Every few months I find myself needing a fresh, strong password for a new server, a database user, or some API key I’m about to rotate. Instead of relying on a browser extension or an online generator (which I never fully trust with something as sensitive as a password), I built my own password generator directly in Bash. It runs locally, it’s fast, and I can tweak it however I like. In this article I’ll walk you through exactly how I built it, from the simplest one-liner to a fully-featured script with options, validation, and security safeguards.

Why Build a Password Generator in Bash?

Bash is already installed on almost every Linux server and macOS machine I touch, so there’s no dependency to install and no third-party tool to trust. A password generator written in Bash is:

The Simplest Version: A One-Liner

Before building anything elaborate, it helps to understand the core idea. The simplest password generator in Bash looks like this:

< /dev/urandom tr -dc 'A-Za-z0-9' | head -c 16; echo

Here’s what’s happening internally:

This one-liner works, but it has no options, no way to include symbols, and no error handling. Let’s build something more robust.

Step-by-Step: Building a Full Script

I like to structure my scripts so they accept flags, similar to a real CLI tool. Here’s the full script I actually use:

#!/usr/bin/env bash
set -euo pipefail

# Default configuration
LENGTH=16
USE_SYMBOLS=false
COUNT=1

usage() {
    echo "Usage: $0 [-l length] [-s] [-n count]"
    echo "  -l  Password length (default: 16)"
    echo "  -s  Include symbols"
    echo "  -n  Number of passwords to generate (default: 1)"
    exit 1
}

while getopts "l:sn:h" opt; do
    case "$opt" in
        l) LENGTH="$OPTARG" ;;
        s) USE_SYMBOLS=true ;;
        n) COUNT="$OPTARG" ;;
        h) usage ;;
        *) usage ;;
    esac
done

if ! [[ "$LENGTH" =~ ^[0-9]+$ ]] || [ "$LENGTH" -lt 8 ]; then
    echo "Error: length must be a number >= 8" >&2
    exit 1
fi

CHARSET='A-Za-z0-9'
if [ "$USE_SYMBOLS" = true ]; then
    CHARSET='A-Za-z0-9!@#$%^&*()_+-='
fi

generate_password() {
    tr -dc "$CHARSET" < /dev/urandom | head -c "$LENGTH"
    echo
}

for ((i = 0; i < COUNT; i++)); do
    generate_password
done

Save this as pwgen.sh, make it executable, and run it:

chmod +x pwgen.sh
./pwgen.sh -l 20 -s -n 3

Example output:

xT9!mQ2z@Lp8#Vr6_Kd1
qW3z*Nf7$Ht2^Bc9=Ry5
Zm4@Xk8!Gs1#Pn6_Vq3+

Explaining the Script Internally

Real-World Use Cases

I use variations of this script for:

A common pattern I use is writing the generated password straight into a secrets manager instead of a file:

PASSWORD=$(./pwgen.sh -l 24 -s)
vault kv put secret/myapp/db-password value="$PASSWORD"

Automation Example: Auto-Rotating a Service Account Password

Here’s a small automation snippet I run on a schedule via cron to rotate a service account password monthly:

#!/usr/bin/env bash
set -euo pipefail

NEW_PASS=$(tr -dc 'A-Za-z0-9!@#$%^&*' < /dev/urandom | head -c 24)
echo "Rotating password for svc_account..."
echo "svc_account:${NEW_PASS}" | chpasswd
echo "${NEW_PASS}" > /root/.svc_account_pass
chmod 600 /root/.svc_account_pass

Scheduled with:

0 3 1 * * /usr/local/bin/rotate_password.sh

Security Considerations

This is the part I take most seriously, because a password generator is only as good as its randomness and its handling of the output.

Optimization Tips

Troubleshooting

Common Mistakes to Avoid

FAQs

Is /dev/urandom really secure enough for passwords? Yes. On modern Linux kernels, /dev/urandom is backed by a cryptographically secure pseudo-random number generator and is considered safe for generating passwords, keys, and tokens.

Can I generate passwords without symbols for systems that don’t allow them? Yes, just omit the -s flag in the script above, and it will default to alphanumeric-only output.

How long should my generated passwords be? I personally default to at least 16 characters for user accounts and 24+ for service accounts or API keys.

Can this script run on macOS? Yes, macOS ships with Bash (or you can install a newer version via Homebrew) and /dev/urandom behaves the same way.

Summary

Building a password generator in Bash turned out to be a great way to understand how randomness, character filtering, and shell scripting all fit together. Starting from a simple tr/urandom one-liner, I extended it into a flexible script with flags for length, symbols, and batch generation, while keeping security front and center by relying on /dev/urandom instead of Bash’s weaker built-in randomness.

References

Exit mobile version