2
\$\begingroup\$

Yesterday, I was bored and decided to write a random password generator. At first it used numerous temporary files, changed that by using arrays.

This was written on OS X and should work on Linux with minor tweaks (at least change all gshuf to shuf).

Example use:

$ pw -c 3 -l 20 -a b -nsr
Vh.9"7`gN;;$kV*/LddE
q);S;byf/._Z8;S1|>Kb
3<*FfS&Y&}wD17l[M?y{

Your thoughts and ideas are welcome.

#!/bin/sh
#
#
# Random Password Generator
#
#
#set -x
COUNT=""
ALPHA=""
NUMERICAL=0
SPECIAL=0
STRING_LENGTH=""
RESHUF=0
# delimiters
nu="0-9"
al="a-z"
au="A-Z"
sc="!\"#$%&\'()*+,-./:;<=>?@[\]^_\`{|}~"
urandom_cat() {
# function generates random characters, delimiter gets send from function gen_char_pw
DELIMITER=1ドル
 cat /dev/urandom | env LC_CTYPE=C tr -cd $DELIMITER | head -c 1000
}
usage() {
cat << EOF
This script generates a number of passwords.
usage: 0ドル -c <number> -l <number> -a <option> -nsr
 c and l arguments are REQUIRED!
 at least one argument out of a, n and s is required
ARGUMENTS
 -h Show this message
 -c number Number of passwords to create
 -l number Length of password
 -a u/l/b Use alphabet (upper-case/lower-case/both)
 -n Use numbers
 -s Use special characters
 -r Reshuffle characters of final password (pretty much useless, but mehh, who cares?)
EOF
}
print_pw() {
# length of phrase gets checked 
# in case reshuffle option is ticked, phrase gets reshuffeld and printed out
# else phrase gets printed out. COUNT gets reduced by one
 if [[ "$(printf '%s' "$pw" | wc -m)" -eq $STRING_LENGTH ]] ; then
 if [[ $RESHUF -eq 1 ]] ; then 
 echo "$pw" | fold -w 1 | gshuf | tr -d "\\\r\n" ; echo
 else
 echo "$pw"
 fi
 COUNT=$(($COUNT-1)) 
 fi
}
gen_char_pw() {
# send delimiter to urandom_cat and fills characters into an array
# then random characters from the array get combined to a password
# trailing newline gets cut off and phrase gets cut to desired length
DELIMITER=1ドル 
 i=0
 for char in "$((urandom_cat $DELIMITER) | fold -w 1)" ; do
 CHARS[$i]=$char
 i=$(($i+1))
 done
 pw="$(gshuf -e "${CHARS[@]}" 2>/dev/null | tr -d "\\\r\n" | head -c $STRING_LENGTH)"
}
gen_pw() {
# lower-case letters
 if [[ $ALPHA == l && $NUMERICAL -eq 0 && $SPECIAL -eq 0 ]] ; then
 gen_char_pw $al
 case "$pw" in
 # contained characters get checked 
 *[a-z]*)
 print_pw
 ;;
 esac
# upper_case letters
 elif [[ $ALPHA == u && $NUMERICAL -eq 0 && $SPECIAL -eq 0 ]] ; then
 gen_char_pw $au 
 case "$pw" in 
 *[A-Z]*)
 print_pw
 ;;
 esac
# numbers
 elif [[ -z $ALPHA && $NUMERICAL -eq 1 && $SPECIAL -eq 0 ]] ; then
 gen_char_pw $nu 
 case "$pw" in 
 *[0-9]*)
 print_pw
 ;;
 esac
# special-characters
 elif [[ -z $ALPHA && $NUMERICAL -eq 0 && $SPECIAL -eq 1 ]] ; then
 gen_char_pw $sc 
 case "$pw" in 
 *[\!\"\#\$\%\&\'\(\)\*\+,円\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~]*)
			print_pw
			;;
		esac
# lower-case and upper-case letters
	elif [[ $ALPHA == b && $NUMERICAL -eq 0 && $SPECIAL -eq 0 ]] ; then
		gen_char_pw $al$au
		case "$pw" in 
			*[A-Z]*)
			case "$pw" in 
				*[a-z]*)
				print_pw
			esac
		esac
# lower-case letters and numbers
	elif [[ $ALPHA == l && $NUMERICAL -eq 1 && $SPECIAL -eq 0 ]] ; then
		gen_char_pw $al$nu
		case "$pw" in 
			*[a-z]*) 
			case "$pw" in 
				*[0-9]*)
				print_pw
				;;
			esac
		esac
# upper-case letters and numbers
	elif [[ $ALPHA == u && $NUMERICAL -eq 1 && $SPECIAL -eq 0 ]] ; then
		gen_char_pw $au$nu
		case "$pw" in 
			*[A-Z]*) 
			case "$pw" in 
				*[0-9]*)
				print_pw
				;;
			esac
		esac
# numbers and special-characters
	elif [[ -z $ALPHA && $NUMERICAL -eq 1 && $SPECIAL -eq 1 ]] ; then
		gen_char_pw $nu$sc
		case "$pw" in 
			*[0-9]*) 
			case "$pw" in 
				*[\!\"\#\$\%\&\'\(\)\*\+,円\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~]*)
 print_pw
 ;;
 esac
 esac
# lower-case letters and special-characters
 elif [[ $ALPHA == l && $NUMERICAL -eq 0 && $SPECIAL -eq 1 ]] ; then
 gen_char_pw $al$sc 
 case "$pw" in 
 *[a-z]*)
 case "$pw" in 
 *[\!\"\#\$\%\&\'\(\)\*\+,円\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~]*)
 print_pw
 esac
 esac
# upper-case letters and special-characters
 elif [[ $ALPHA == u && $NUMERICAL -eq 0 && $SPECIAL -eq 1 ]] ; then
 gen_char_pw au$sc
 case "$pw" in 
 *[A-Z]*)
 case "$pw" in 
 *[\!\"\#\$\%\&\'\(\)\*\+,円\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~]*)
				print_pw
			esac
		esac
# lower-case letters, numbers and special-characters
	elif [[ $ALPHA == l && $NUMERICAL -eq 1 && $SPECIAL -eq 1 ]] ; then
		gen_char_pw $al$nu$sc	
		case "$pw" in 
			*[0-9]*) 
			case "$pw" in 
				*[a-z]*)
				case "$pw" in 
					*[\!\"\#\$\%\&\'\(\)\*\+,円\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~]*)
 print_pw
 esac
 esac
 esac
# upper-case letters, numbers and special-characters
 elif [[ $ALPHA == u && $NUMERICAL -eq 1 && $SPECIAL -eq 1 ]] ; then
 gen_char_pw $au$nu$sc
 case "$pw" in 
 *[0-9]*) 
 case "$pw" in 
 *[A-Z]*)
 case "$pw" in 
 *[\!\"\#\$\%\&\'\(\)\*\+,円\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~]*)
 print_pw
 esac
 esac
 esac
# lower-case and upper-case letters, numbers
 elif [[ $ALPHA == b && $NUMERICAL -eq 1 && $SPECIAL -eq 0 ]] ; then
 gen_char_pw $al$au$nu
 case "$pw" in 
 *[0-9]*) 
 case "$pw" in 
 *[A-Z]*)
 case "$pw" in 
 *[a-z]*)
 print_pw
 esac
 esac
 esac
# lower-case and upper-case letters, special-characters
 elif [[ $ALPHA == b && $NUMERICAL -eq 0 && $SPECIAL -eq 1 ]] ; then
 gen_char_pw $al$au$sc
 case "$pw" in 
 *[A-Z]*)
 case "$pw" in 
 *[a-z]*)
 case "$pw" in 
 *[\!\@\#\$\%\^\&\*\(\)\_\+\?\>\<\~\`\;\']*)
					print_pw
				esac
			esac
		esac
# lower-case and upper-case letters, numbers and special-characters
	elif [[ $ALPHA == b && $NUMERICAL -eq 1 && $SPECIAL -eq 1 ]] ; then
		gen_char_pw $al$au$nu$sc
		case "$pw" in 
			*[0-9]*) 
			case "$pw" in 
				*[A-Z]*)
				case "$pw" in 
					*[a-z]*)
					case "$pw" in 
						*[\!\@\#\$\%\^\&\*\(\)\_\+\?\>\<\~\`\;\']*)
 print_pw
 esac
 esac
 esac
 esac
 fi
}
while getopts c:a:l:nshr opt ; do
 case "$opt" in
 c) COUNT="2ドル" ;;
 l) STRING_LENGTH="4ドル" ;;
 a) ALPHA="6ドル" ;;
 n) NUMERICAL=1 ;; 
 s) SPECIAL=1 ;;
 r) RESHUF=1 ;;
 --) usage
 exit 1 ;;
 h) usage
 exit 1 ;;
 *) usage
 exit 1 ;;
 esac
done
if [[ -z $COUNT ]] || [[ -z $STRING_LENGTH ]] ; then
 usage
 exit 1
elif [[ -z $ALPHA ]] && [[ $NUMERICAL -eq 0 ]] && [[ $SPECIAL -eq 0 ]] ; then
 usage
 exit 1
fi
while [ $COUNT -gt 0 ]; do
 gen_pw
done
exit 0
Reinderien
70.9k5 gold badges76 silver badges256 bronze badges
asked Oct 16, 2016 at 22:20
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

Seems all clean and proper.

But.

The function gen_pw() is a bit, how shall I put it, longwinded.

You can use variables in sed, too, so something like (in one line for easy C&P)

r1="A-Z"; r2="0-9"; r3="" ; cat /dev/urandom | tr -cd '[:graph:]' | head -c 1000| sed -e "s/[^$r1$r2$r3]//g" | head -c 10

can be done easily

If you base your program on it you can just fill the variables with the chosen characters.

r1="";
r2="";
r3="";
r4="";
if [[ $NUMERICAL -eq 1 ]] ; then
 r1 = $nu;
elif [[ $ALPHA == l ]] || [[ $ALPHA == b ]] ; then
 r2 = $al;
elif [[ $ALPHA == u ]] || [[ $ALPHA == b ]] ; then
 r3 = $au;
elif [[ $SPECIAL -eq 1 ]] ; then
 r4 = $sc;
endif

(above is not tested, just to show what I meant) Then you run the one-liner from the top

cat /dev/urandom | tr -cd '[:graph:]' | head -c 1000| sed -e "s/[^$r1$r2$r3$r4]//g" | head -c $STRING_LENGTH

It is a bit shorter, I think.

You still need to check if the input from the user makes sense, if the output is actually $STRING_LENGTH long (you are using a random source!) and all of the rest, but you already have most, if not all of it. And check if tr -cd '[:graph:]' doesn't let pass too much or too little.

answered Oct 17, 2016 at 1:41
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.