Last active
November 27, 2024 10:52
-
-
Save oleasteo/1936b012b3f88a86ce92036c9110c5f4 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/bin/bash | |
| cmd="$0" | |
| usage() { | |
| cat <<EOL | |
| Usage: $cmd [...OPTIONS] [LENGTH=16] | |
| Generates a random string based on the specified alphabet. If no alphabet is | |
| specified, the \`base\` alphabet is used (alphanumeric and special characters). | |
| OPTIONS | |
| -h | --help Show this message. | |
| -v | --verbose Print charset (as passed to \`tr\`). | |
| -c | --charset CHARS Use custom alphabet. See \`tr\` for syntax. | |
| -n | --length LENGTH Define the output length (default: 16). | |
| -[ludseqxrmabA] | --[ALPHABET] | |
| Use the respective alphabet. | |
| ALPHABETS | |
| -l | --lower a-z | |
| -u | --upper A-Z | |
| -d | --digit 0123456789 | |
| -s | --special !@#%^&*()+_=,.?- | |
| -e | --extra \| ;:/<>[]{}$ | |
| -q | --quote '"\` | |
| -x | --hex 0-9A-F | |
| -r | --url A-Za-z0-9_- | |
| -m | --unambiguous aCDdEeFfGgHhJKLMmNnPQRrTtWY23489 | |
| -a | --alpha Equivalent to \`-lu\`. (lower & upper) | |
| -b | --base Equivalent to \`-luds\` (alpha & digit & special) | |
| -A | --all Equivalent to \`-ludseq\` (base & extra & quote) | |
| EXAMPLES | |
| $cmd --all 8 | |
| Generate a random string with 8 characters, using all builtin alphabets. | |
| $cmd -ad | |
| Generate a random alphanumeric string with 16 characters. | |
| $cmd -m 12 | |
| Generate a random alphanumeric string with 12 unambiguous characters. | |
| $cmd -n 4 -c 0-7 | |
| Generate 4 random octal digits. | |
| EOL | |
| } | |
| ### | |
| # Options | |
| ### | |
| O_LENGTH=16 | |
| O_CHARS= | |
| O_VERBOSE=0 | |
| declare -A O_USE # { [ALPHABET]: 0|1 } | |
| ### | |
| # Constants | |
| ### | |
| declare -A CHARSET # { [ALPHABET]: CHARACTERS } | |
| CHARSET[lower]='a-z' | |
| CHARSET[upper]='A-Z' | |
| CHARSET[digit]='0-9' | |
| CHARSET[special]='!@#%^&*()\-+_=,.?' | |
| CHARSET[extra]='\\| ;:/<>\[\]{}$' | |
| CHARSET[quote]="'"'"`' | |
| CHARSET[hex]="0-9A-F" | |
| CHARSET[url]="A-Za-z0-9_\-" | |
| CHARSET[unambiguous]="aCDdEeFfGgHhJKLMmNnPQRrTtWY23489" | |
| declare -A ALIAS # { [ALIAS]: (...alphabet) } | |
| ALIAS[alpha]="lower upper" | |
| ALIAS[base]="${ALIAS[alpha]} digit special" | |
| ALIAS[all]="${ALIAS[base]} extra quote" | |
| declare -A SHORT # { [ALPHABET]: CHAR } | |
| SHORT[lower]=l | |
| SHORT[upper]=u | |
| SHORT[digit]=d | |
| SHORT[special]=s | |
| SHORT[extra]=e | |
| SHORT[quote]=q | |
| SHORT[hex]=x | |
| SHORT[url]=r | |
| SHORT[unambiguous]=m | |
| SHORT[alpha]=a | |
| SHORT[base]=b | |
| SHORT[all]=A | |
| _set_use() { # _set_use 0|1 [...ALPHABET] | |
| if [ $# -eq 1 ]; then | |
| _set_use $1 "${!CHARSET[@]}" | |
| return | |
| fi | |
| local value=$1 | |
| shift | |
| local name | |
| for name in "$@"; do O_USE[$name]=$value; done | |
| } | |
| _set_use 0 | |
| _set_use 1 ${ALIAS[base]} | |
| ### | |
| # Parse Options | |
| ### | |
| _opts_short() { local ch; for ch in "${SHORT[@]}"; do echo -n "$ch"; done } | |
| _opts_long() { | |
| local name; for name in "${!CHARSET[@]}"; do echo -n ",$name"; done | |
| local alias; for alias in "${!ALIAS[@]}"; do echo -n ",$alias"; done | |
| } | |
| ARGS=$(getopt -o '+'hvc:n:$(_opts_short) --long "help,verbose,charset,length$(_opts_long)" -- "$@") | |
| [[ $? -ne 0 ]] && exit 1 | |
| eval set -- "$ARGS" | |
| ### | |
| # Process Options | |
| ### | |
| _is_custom=0 | |
| _set_custom() { | |
| if [ $_is_custom -eq 0 ]; then | |
| _set_use 0 | |
| _is_custom=1 | |
| fi | |
| } | |
| while true; do | |
| for name in "${!CHARSET[@]}"; do | |
| short="${SHORT[$name]}" | |
| if [ "$1" = "-$short" -o "$1" = "--$name" ]; then | |
| _set_custom | |
| _set_use 1 $name | |
| shift | |
| continue 2 | |
| fi | |
| done | |
| for name in "${!ALIAS[@]}"; do | |
| short="${SHORT[$name]}" | |
| if [ "$1" = "-$short" -o "$1" = "--$name" ]; then | |
| _set_custom | |
| _set_use 1 ${ALIAS[$name]} | |
| shift | |
| continue 2 | |
| fi | |
| done | |
| case "$1" in | |
| -h|--help) | |
| usage | |
| exit 0 | |
| ;; | |
| -v|--verbose) | |
| shift | |
| O_VERBOSE=1 | |
| ;; | |
| -c|--charset) | |
| shift | |
| _set_custom | |
| O_CHARS="$1" | |
| shift | |
| ;; | |
| -n|--length) | |
| shift | |
| O_LENGTH="$1" | |
| shift | |
| if ! [[ "$O_LENGTH" =~ ^[0-9]+$ ]]; then | |
| echo "Error: LENGTH must be a positive integer." | |
| usage | |
| exit 1 | |
| fi | |
| ;; | |
| --) | |
| shift | |
| break | |
| ;; | |
| *) | |
| echo "Error: Unknown option $1" | |
| usage | |
| exit 1 | |
| ;; | |
| esac | |
| done | |
| if [ $# -gt 1 ]; then | |
| echo "Error: Too many arguments: $@" | |
| exit 1 | |
| fi | |
| if [ $# -eq 1 ]; then | |
| O_LENGTH="$1" | |
| shift | |
| if ! [[ "$O_LENGTH" =~ ^[0-9]+$ ]]; then | |
| echo "Error: LENGTH must be a positive integer." | |
| usage | |
| exit 1 | |
| fi | |
| fi | |
| ### | |
| # Collect chars | |
| ### | |
| for name in "${!CHARSET[@]}"; do | |
| if [ "$(echo "${O_USE[$name]}")" -eq 1 ]; then | |
| O_CHARS="$O_CHARS${CHARSET[$name]}" | |
| fi | |
| done | |
| if [ -z "$O_CHARS" ]; then | |
| echo no chars selected | |
| exit 1 | |
| fi | |
| ### | |
| # Print secret | |
| ### | |
| [ -t 1 -a "$O_VERBOSE" -eq 1 ] && echo "Charset: $O_CHARS" && echo -ne "Secret: \033[47;30;1m" | |
| LC_ALL=C tr -dc "$O_CHARS" < /dev/urandom | head -c $O_LENGTH | |
| [ -t 1 ] && echo -e '\033[0m' || true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment