Skip to content

Instantly share code, notes, and snippets.

@earthgecko
Last active December 6, 2024 04:07
Show Gist options
  • Save earthgecko/3089509 to your computer and use it in GitHub Desktop.
Save earthgecko/3089509 to your computer and use it in GitHub Desktop.
shell/bash generate random alphanumeric string
#!/bin/bash
# bash generate random alphanumeric string
#
# bash generate random 32 character alphanumeric string (upper and lowercase) and
NEW_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
# bash generate random 32 character alphanumeric string (lowercase only)
cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1
# Random numbers in a range, more randomly distributed than $RANDOM which is not
# very random in terms of distribution of numbers.
# bash generate random number between 0 and 9
cat /dev/urandom | tr -dc '0-9' | fold -w 256 | head -n 1 | head --bytes 1
# bash generate random number between 0 and 99
NUMBER=$(cat /dev/urandom | tr -dc '0-9' | fold -w 256 | head -n 1 | sed -e 's/^0*//' | head --bytes 2)
if [ "$NUMBER" == "" ]; then
NUMBER=0
fi
# bash generate random number between 0 and 999
NUMBER=$(cat /dev/urandom | tr -dc '0-9' | fold -w 256 | head -n 1 | sed -e 's/^0*//' | head --bytes 3)
if [ "$NUMBER" == "" ]; then
NUMBER=0
fi
@Tagima
Copy link

Tagima commented Sep 3, 2020

Why don't use head -c instead of fold? Benefits: performance, works on Git Bash under Windows too.

cat /dev/urandom | tr -dc 'a-z0-9' | head -c 32

https://gist.github.com/fnkr/de448cbf9f45038d69bb

As @fnkr said, using head -c gives you a better performance. But I'd sugest using head when reading /dev/urandom since cat may cause an out of memory issue. Like this:

test=$(head -c 4096 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 4096 | head -n 1)

In this specific case I had to generate a random string with 4096 bytes programmatically. Using cat /dev/urandom was making my application hang since this file is a bit too large.

@earthgecko
Copy link
Author

earthgecko commented Sep 3, 2020

@Tagima using head instead of cat on /dev/urandom does not give the same results. You probably want to check all of your output is 4096 bytes as head will not necessarily generate the exact size in all innovacations or use head -c 6096 /dev/urandom as you fold at 4096, 6096 will ensure you have sufficient.

me@host:~$ head -c 32 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
1WiaY4pBbvme@host:~$
me@host:~$ cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
SldlezjjelFEKScjS9SFEbdWoQeptU95
me@host:~$
me@host:~$ head -c 32 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
oHMLHwUme@host:~$ head -c 32 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
qdNQZtFGme@host:~$ head -c 32 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
AtBByXkB7CKme@host:~$ head -c 32 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
p12kCWu77me@host:~$ head -c 32 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
9owjuxHme@host:~$ head -c 32 /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
j9yEZeDime@host:~$
me@host:~$ cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
WJIRqP4qYnJWHAKu8aIM9kj5K9oIxHp3
me@host:~$ cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
hUMa4Nc1y7DgZmb3uDKTivv1OvQTHWIL
me@host:~$ cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
JDwO1jdz8Vsrl4tH5xx4OmsLwhhViQ3X
me@host:~$ cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
ssA2D7hj1cXRxVwFHHHa6AUqGk7NL1k7
me@host:~$ cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1
YReUN6A7GEG6f69Jz4VuFpfPVIZiISFt
me@host:~$

@Tagima
Copy link

Tagima commented Sep 3, 2020

@earthgecko Thank you!

@zakstar
Copy link

zakstar commented Sep 3, 2020

When I try to use it the command just doesn't exit. I assume it is because there is no EOF for cat to exit?

@johnsout
Copy link

johnsout commented Sep 9, 2020

use cat /dev/urandom | tr -dc 'a-za-z0-9' | fold -w 8 | head -n 1 for lowercase generator

@amirofski
Copy link

Thanks

@amirphl
Copy link

amirphl commented Oct 30, 2020

Very nice and useful.

@duccas
Copy link

duccas commented Nov 14, 2020

This is a good script, but what about the random from 0.001 to 1?

@earthgecko
Copy link
Author

@icohigh - random float between 0 and 1 (to random precise between 1 and 3)
It is not pure bash, but this gist was not about random floats it was about random alphanumeric strings.

python -c "exec(\"import random\nprint(round(random.uniform(0, 1), int(random.uniform(1, 4))))\")"

If you did not want random precise, e.g. 0.111, 0.123, 0.7, 0.356

python -c "exec(\"import random\nprint(round(random.uniform(0, 1), 3))\")"

@ushiocheng
Copy link

Exactly what I need ;)

@ushiocheng
Copy link

ushiocheng commented Nov 17, 2020

Also a much more sketchy but works way

head -c 1024 /dev/urandom | base64 | tr -cd "[:upper:][:digit:]" | head -c 32

tested on macOS 10.15.7
it does not promise a success, but after generating 1024 chars on random, the chance of it not containing 32 upper case and number is astronomically slim.

If you are curious, the chance of not generating 512 char and only have <32 upper&digit is 2.051*10^-195. and the chance of failing of 1024 is ....... ok, mathmetica literately tells me it "is too small to represent as a normalized machine number" 😆 and it is about 10^-400

and btw it takes 7ms to execute; on my machine 🤣

@GCV-Sleeper-Service
Copy link

Which one of all the different options given above is the fastest?
As an example - if one wants to generate 10000 lines each 16 random chars long using 0-9a-zA-Z as a dictionary, which method would be the fastest?

@ljamel
Copy link

ljamel commented Apr 25, 2021

If you need add spéciale caractère

echo NEW_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9&-@' | fold -w 10 | head -n 1)

@sergeyklay
Copy link

sergeyklay commented Apr 25, 2021

Generate UUID-like strings:

$ od -x /dev/urandom | head -1 | awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}'
# 14e9710d-e38a-fbba-4a97-a8972fbf2fd0

This bypasses any neccessity to installsoftware like uuidgen or external modules for Perl or Python. Tested on macOs and Linux.

@itslevir
Copy link

this is great! thanks!

@aurelienlair
Copy link

cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1 (2nd command) is not generating lowercase only while this one yes
cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 32 | head -n 1

@pier4r
Copy link

pier4r commented Jul 25, 2021

alternative on systems that don't have many packages (openwrt old versions)

dd if=/dev/urandom bs=10 count=20 | tr -dc 'a-zA-Z0-9' | xargs echo

Adjust bs and count as you wish.

@mkows
Copy link

mkows commented Oct 13, 2021

The following seems to work fine both on Linux and macOS (4 alphanum characters):

cat /dev/urandom | env LC_CTYPE=C tr -dc 'a-z0-9' | fold -w 4 | head -n 1

@htxuuu
Copy link

htxuuu commented Dec 16, 2021

Thanks

@UdaniWijesinghe
Copy link

Can someone help me to generate random letters only?

@earthgecko
Copy link
Author

@UdaniWijesinghe just remove the 0-9

# bash generate random 32 character alphabetic only string (upper and lowercase) and 
NEW_UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z' | fold -w 32 | head -n 1)

# bash generate random 32 character alphabetic string (lowercase only)
cat /dev/urandom | tr -dc 'a-z' | fold -w 32 | head -n 1

@robertodormepoco
Copy link

robertodormepoco commented Jan 11, 2022

on macOS (/dev/urandom does not spits out any valid CTYPE, is this M1 related?)

# generate single letter in range a-z
head /dev/urandom | base64 | tr -dc 'a-z' | fold -w 1 | head -n 1

@pier4r
Copy link

pier4r commented Jan 11, 2022

The base64 approach is interesting to make every byte count (for a-zA-Z and 0-9). only I am not really sure if base64 maps the bytes uniformingly on a-zA-Z0-9 . I didn't check so far, has anyone experience?

@robertodormepoco
Copy link

@pier4r that's a fair question, though base64 breaks streams in 6bits chars, given that the source of randomnes should minimize the correlation between the previous N bits and the current ones, the only reduction of information is due to the tr step, which is intrinsic in the goal of the opertions (generate range of alphachars/numbers/both)

@NicolasGoeddel
Copy link

base64 should be the best thing you can do. This way no incoming bit will be ignored. tr on the other hand is not the best thing in my opinion. But it also would be a bit more complicated if you always want to make every bit count.

@GCV-Sleeper-Service
Copy link

GCV-Sleeper-Service commented Jan 11, 2022

When generating one or two 10-20 char length strings which method you pick up probably is not that important.

How about putting the question differently - which method would be least resource-intensive and won't require installation of additional tool? Let's imagine you need to generate 5000 strings each 160 char length.

@pier4r
Copy link

pier4r commented Jan 11, 2022

invisible see https://gist.github.com/earthgecko/3089509#gistcomment-3827754 (achieved on a very small footprint OS, openwrt)

@GCV-Sleeper-Service
Copy link

@pier4r Thanks. But what performance would look like compared to other methods?

@pier4r
Copy link

pier4r commented Jan 12, 2022

@invisible999 don't know, one needs to make a benchmark with the various proposed methods (and likely others published elsewhere)

@dagreatpyro22
Copy link

how do i generate the string cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1 but have the first half as dedicated set characters

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment