#!/bin/bash set -euo pipefail # ── Defaults ───────────────────────────────────────────────────────── DEFAULT_LENGTH=16 CHARSET="alnum" # alnum | ascii # ── Usage ──────────────────────────────────────────────────────────── usage() { cat <&2; usage ;; *) break ;; esac done LENGTH="${1:-$DEFAULT_LENGTH}" # ── Validate length ───────────────────────────────────────────────── if ! [[ "$LENGTH" =~ ^[0-9]+$ ]] || (( LENGTH <= 0 )); then echo "Error: length must be a positive integer, got '${LENGTH}'" >&2 exit 1 fi # ── Generate password ─────────────────────────────────────────────── # tr character classes: # alnum -> [A-Za-z0-9] # ascii -> [A-Za-z0-9] + special characters generate_password() { local len="$1" local filter case "$CHARSET" in alnum) filter='A-Za-z0-9' ;; ascii) filter='A-Za-z0-9!@#$%^&*_+\-=' ;; esac # Read enough random bytes to guarantee the desired length after filtering. # tr may exit with SIGPIPE once head has enough bytes — that is expected. LC_ALL=C tr -dc "$filter" /dev/null; then echo -n "$PASSWORD" | wl-copy echo "(copied to clipboard)" >&2 else echo "Warning: wl-copy not found (install wl-clipboard)" >&2 fi fi