How to generate thousands of usernames and halfway decent passwords with Bash💯💯
Tags: bash, linux, tutorial
Published: 2021-05-17 09:09:59

Have you ever needed, say, an astonishing number of user names and passwords? I recently did and thought to myself: **"I can automate that!"**

But, first of all...

# What kind of user names and passwords are we talking about?

Some tools use them a lot, especially for anonymous users: Positive adjectives together with animal names. For example: "Knowledgeable ibex" or... See, it's quite hard to come up with those, especially if English isn't your first language. I was thinking for a good 5 minutes and the ibex was the only example I could come up with. To be fair, I haven't had a coffee yet... I'm getting off topic. Where was I? Anyways, you get the idea: "Positive adjective + animal". Such user names can be used as testing data, anonymous users or basically any use case where a lot of unique user names are necessary.

The password should ideally be something random, too. 16 characters, including numbers, uppercase and lowercase letters, and some special characters like `!._-,;?^$+"*%&/()=`.

# Getting the data

So, let's first gather some data. I need animals and positive adjectives. I found a pretty large list of animals over at [a-z-animals.com](https://a-z-animals.com/animals/) and a large list of positive adjectives at [grammar.yourdictionary.com](https://grammar.yourdictionary.com/parts-of-speech/adjectives/list-of-positive-adjectives.html). Perfect. I create two lists, separated by newlines and put them in two files, namely `animals.txt` and `adjectives.txt`. So far so good, that's all the data I need, the rest is done with Bash.

# Mapping a file using `mapfile`

Since Bash 4.0 there's a neat command called [`mapfile`](https://ss64.com/bash/mapfile.html) that reads a file line by line and creates an array out of it. I use this to read out all adjectives and animals:

```bash
#!/bin/bash

mapfile ADJECTIVES < ./adjectives.txt
mapfile ANIMALS < ./animals.txt
```

# Generating the usernames

To generate a large number of user names, I could now randomly select one of each and concatenate them:

```bash
#!/bin/bash

mapfile ADJECTIVES < ./adjectives.txt
mapfile ANIMALS < ./animals.txt

RANDOM_ADJECTIVE=$(echo ${ADJECTIVES[$RANDOM % ${#ADJECTIVES[@]} ]})
RANDOM_ANIMAL=$(echo ${ANIMALS[$RANDOM % ${#ANIMALS[@]} ]})
```

I'm using `$RANDOM` here to generate a random number. This random number mod the size of the list guarantees to create a random number that is one of the array indices of that list. with `${LIST[...]}` I then get the randomly chosen element.

Next, I concatenate them and massage the string a bit:

```bash
# ...

RANDOM_ADJECTIVE=$(echo ${ADJECTIVES[$RANDOM % ${#ADJECTIVES[@]} ]})
RANDOM_ANIMAL=$(echo ${ANIMALS[$RANDOM % ${#ANIMALS[@]} ]})

# Concat
ADJECTIVE_ANIMAL=$(echo $RANDOM_ADJECTIVE-$RANDOM_ANIMAL)

# Make it machine readable
MACHINEREADABLE=$(echo $ADJECTIVE_ANIMAL | iconv -t ascii//TRANSLIT | sed -r s/[^a-zA-Z0-9]+/-/g | tr A-Z a-z)
```

First, all characters that are not ASCII are transliterated as such using `iconv`, for example `äàá` should all become `a`. Then I replace all non-alphanumeric characters with `-` using `sed -r`. In the last step, I transform the string to lower case using `tr`.

This now produces things like these:

```
fantastic-poodle
giving-dalmadoodle
glowing-sheepadoodle
focused-pointer
articulate-fly
glittering-stag-beetle
articulate-leopard-frog
unique-estrela-mountain-dog
excellent-russell-terrier
splendid-echidna
brilliant-italian-greyhound
magnificent-barnacle
polite-saint-bernard
glittering-eastern-bluebird
imaginative-manta-ray
willing-doberman-pinscher
faithful-drever
```

Gotta love the `fantastic poodle`!

# Generating the password

Now for the fun part: Generating a decent password. I rely on the OS here by using `/dev/urandom`:

```bash
# ...
PASSWORD=$(cat /dev/urandom | tr -cd '[:graph:]' | fold -w 24 | head -n 1)
```

So a random bit string is read from `/dev/urandom`, which is then transformed into a string containing all printable characters (using `[:graph:]`). The string is then folded into words with 24 characters length. The first one of these words is then selected with `head -n 1`. This produces passwords like these:

```
Lb6UR+-iF5xj5`q}g1t(d3Dn
W]Aai"t,<H:)M[QV$lJi~H.%
V~2=Jq2InaGAU^Y\Uzx^9500
+XuY\[7-]g<[FyYKpE+"G[r7
=LYmTQ$D"}MN5]wC{$;ySE.}
jsE:y+A)NV{0CHvO-D)wazx*
2TB1~~Q~8d<_'Zj)ED$1yQ8\
!=bV.w0ko0F/Y"98M`ZzS1'%
IVmd4XfNR3'iffVUuwJ"[_IT
CR,Iq`},c5X7JdFfF7b@bi3!
:{y%'0%M~ys1lhR=$d,xNE"%
D*0AJikOKcBUo&6hku]g<(ZC
fQK'%R8("+*/o;.Vfd<7;/"W
```

Looks pretty secure to me. Let's test `=LYmTQ$D"}MN5]wC{$;ySE.}` with some "password security testing tools" that a popular search engine is suggesting.

![Password strength checker number 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tkm543hw9ihij0guj8jh.png)

![Password strength checker number 2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rke1vz4ue0sr9ut93jz0.png)

![Password strength checker number 3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/swakq5rrl3wifs96s0q7.png)

Ok, those numbers are dizzying, but differ widely. Here's a checker that actually tells you how they calculate the strength of a password:

![A verbose password strength checker](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sqeglocvi25zanu63dmv.png)

Sounds good to me. For a one time login/password, that should be more than enough.

# The final script

I also added a loop around the thing to generate multiple usernames and passwords.

```bash
#!/bin/bash

mapfile ANIMALS < ./animals.txt
mapfile ADJECTIVES < ./adjectives.txt

for ((N=0; N<$1; N++))
do
  RANDOM_ADJECTIVE=$(echo ${ADJECTIVES[$RANDOM % ${#ADJECTIVES[@]} ]})
  RANDOM_ANIMAL=$(echo ${ANIMALS[$RANDOM % ${#ANIMALS[@]} ]})

  ADJECTIVE_ANIMAL=$(echo $RANDOM_ADJECTIVE-$RANDOM_ANIMAL)

  MACHINEREADABLE=$(echo $ADJECTIVE_ANIMAL | iconv -t ascii//TRANSLIT | sed -r s/[^a-zA-Z0-9]+/-/g | tr A-Z a-z)
  
  PASSWORD=$(cat /dev/urandom | tr -cd '[:graph:]' | fold -w 24 | head -n 1)
  
  echo $MACHINEREADABLE $PASSWORD
done
```

The first parameter of the script now determines the number of user name/password pairs generated:

```
user@dir $ ./create-users.sh 10
amazing-carp ACytS~_(Z+|<4fi}V<Mjy*g~
splendid-glen-of-imaal-terrier \#AK@]m[7R*>hzuOO^%r1ZY@
capable-blue-lacy-dog ?;CnSkJW's.<|PN:wQDOikI/
considerate-eastern-lowland-gorilla zQxT`]miaE4m$*W`Z8tpa@N5
powerful-puffin Kh=SUqh<no18.[A$Fea+LLXg
philosophical-bernese-shepherd 1h),NV(hi<vG)~{A]x^2I?bH
hardworking-american-foxhound \pbzUC~*~VLk}$wy6dHWFcw(
amazing-canadian-eskimo-dog -x{8PIwiI$/NcZ5#}'$Wlod-
responsible-umbrellabird eDzW\1H/U/(L_fHS^(U&:ltd
agreeable-termite |Kcgx-go>$7`:}nn7-\P&"}b
```

Amazing! Only need to copy/paste that now.

**Whats your favorite positive-adjective + animal username you could generate? Leave a comment!**

---

*I hope you enjoyed reading this article as much as I enjoyed writing it! If so, leave a* ❤️ *or a* 🦄*! I write tech articles in my free time and like to drink coffee every once in a while.*

*If you want to support my efforts,* [*buy me a coffee* ☕](http://buymeacoffee.com/pthormeier) *or* [*follow me on Twitter* 🐦](https://twitter.com/pthormeier)*!* *You can also support me directly via [Paypal](https://www.paypal.me/pthormeier)!*

[![Buy me a coffee button](https://dev-to-uploads.s3.amazonaws.com/i/x55hp6jopwyy161d8e2u.png)](http://buymeacoffee.com/pthormeier)