/home/alex/dev/passwd-gen.sh (2)

From RaySoft
#!/bin/bash -
# ------------------------------------------------------------------------------
# passwd-gen.sh
# =============
#
# Scope     Native
# Copyright (C) 2024 by RaySoft, Zurich, Switzerland
# License   GNU General Public License (GPL) 2.0
#           https://www.gnu.org/licenses/gpl2.txt
#
# ------------------------------------------------------------------------------

set -o 'noglob' -o 'nounset' -o 'pipefail' # -o 'xtrace' -o 'errexit'

# ------------------------------------------------------------------------------

LENGTH=25
AMOUNT=10

UPPER='A-Z'
LOWER='a-z'
NUMBER='0-9'
SPECIAL='_,.!?&%=/*+-'

# ------------------------------------------------------------------------------

BC=('/usr/bin/bc' '-l')
CUT=('/usr/local/bin/gcut')
OPENSSL=('/usr/local/bin/openssl')
TR=('/usr/local/bin/gtr' '-cd')
WC=('/usr/local/bin/gwc' '-c')

# ------------------------------------------------------------------------------

if [[ ${LENGTH} -lt 6 ]]; then
  echo "$0(${LINENO}): Password LENGTH must be at least 6 characters long."

  exit 1
fi

if [[ ${AMOUNT} -lt 1 ]]; then
  echo "$0(${LINENO}): Password AMOUNT must be at least 1."

  exit 1
fi

# ------------------------------------------------------------------------------

count=0
pool=$(( 10 * LENGTH ))

min=( $("${BC[@]}" <<<"
  define int(x) {
    s = scale; scale = 0; x /= 1; scale = s; return x
  }

  define round(x) {
    if (x < 0) x -= 0.5 else x += 0.5; return int(x)
  }

  round(${LENGTH} / 4); round(${length} / 8)
") )

while [[ ${count} -lt ${AMOUNT} ]]; do
  passwd=$( \
    "${OPENSSL[@]}" rand ${pool} \
    | "${TR[@]}" "${UPPER}${LOWER}${NUMBER}${SPECIAL}" \
    | "${CUT[@]}" -c "1-${LENGTH}" \
  )

  if [[ ${passwd:0:1} =~ [${UPPER}${LOWER}] \
     && ${passwd: -1} =~ [${UPPER}${LOWER}] ]]; then
    if [[ $("${TR[@]}" "${SPECIAL}" <<<"${passwd}" | "${WC[@]}") -ge ${min[1]} \
       && $("${TR[@]}" "${NUMBER}" <<<"${passwd}" | "${WC[@]}") -ge ${min[1]} \
       && $("${TR[@]}" "${LOWER}" <<<"${passwd}" | "${WC[@]}") -ge ${min[0]} \
       && $("${TR[@]}" "${UPPER}" <<<"${passwd}" | "${WC[@]}") -ge ${min[0]} ]]; then
      echo "${passwd}"

      ((count+=1))
    fi
  fi
done

# ------------------------------------------------------------------------------

exit 0

Usage

~/dev/passwd-gen.sh