'Using "$RANDOM" to generate a random string in Bash

I am trying to use the Bash variable $RANDOM to create a random string that consists of 8 characters from a variable that contains integer and alphanumeric digits, e.g., var="abcd1234ABCD".

How can I do that?



Solution 1:[1]

Use parameter expansion. ${#chars} is the number of possible characters, % is the modulo operator. ${chars:offset:length} selects the character(s) at position offset, i.e. 0 - length($chars) in our case.

chars=abcd1234ABCD
for i in {1..8} ; do
    echo -n "${chars:RANDOM%${#chars}:1}"
done
echo

Solution 2:[2]

For those looking for a random alpha-numeric string in bash:

LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 64

The same as a well-documented function:

function rand-str {
    # Return random alpha-numeric string of given LENGTH
    #
    # Usage: VALUE=$(rand-str $LENGTH)
    #    or: VALUE=$(rand-str)

    local DEFAULT_LENGTH=64
    local LENGTH=${1:-$DEFAULT_LENGTH}

    LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c $LENGTH
    # LC_ALL=C: required for Mac OS X - https://unix.stackexchange.com/a/363194/403075
    # -dc: delete complementary set == delete all except given set
}

Solution 3:[3]

Another way to generate a 32 bytes (for example) hexadecimal string:

xxd -l 32 -c 32 -p < /dev/random

add -u if you want uppercase characters instead.

Solution 4:[4]

OPTION 1 - No specific length, no openssl needed, only letters and numbers, slower than option 2

sed "s/[^a-zA-Z0-9]//g" <<< $(cat /dev/urandom | tr -dc 'a-zA-Z0-9!@#$%*()-+' | fold -w 32 | head -n 1)

DEMO: x=100; while [ $x -gt 0 ]; do sed "s/[^a-zA-Z0-9]//g" <<< $(cat /dev/urandom | tr -dc 'a-zA-Z0-9!@#$%*()-+' | fold -w 32 | head -n 1) <<< $(openssl rand -base64 17); x=$(($x-1)); done

Examples:

j0PYAlRI1r8zIoOSyBhh9MTtrhcI6d
nrCaiO35BWWQvHE66PjMLGVJPkZ6GBK
0WUHqiXgxLq0V0mBw2d7uafhZt2s
c1KyNeznHltcRrudYpLtDZIc1
edIUBRfttFHVM6Ru7h73StzDnG

OPTION 2 - No specific length, openssl needed, only letters and numbers, faster than option 1

openssl rand -base64 12 # only returns

rand=$(openssl rand -base64 12) # only saves to var

sed "s/[^a-zA-Z0-9]//g" <<< $(openssl rand -base64 17) # leave only letters and numbers
# The last command can go to a var too.

DEMO: x=100; while [ $x -gt 0 ]; do sed "s/[^a-zA-Z0-9]//g" <<< $(openssl rand -base64 17); x=$(($x-1)); done

Examples:

9FbVwZZRQeZSARCH
9f8869EVaUS2jA7Y
V5TJ541atfSQQwNI
V7tgXaVzmBhciXxS

Solution 5:[5]

Not using $RANDOM, but worth mentioning.

Using shuf as source of entropy (a.k.a randomness) (which, in turn, may use /dev/random as source of entropy. As in `shuf -i1-10 --random-source=/dev/urandom) seems like a solution that use less resources:

$ shuf -er -n8  {A..Z} {a..z} {0..9} | paste -sd ""
tf8ZDZ4U

Solution 6:[6]

head -1 <(fold -w 20  <(tr -dc 'a-zA-Z0-9' < /dev/urandom))

This is safe to use in bash script if you have safety options turned on:

set -eou pipefail

This is a workaround of bash exit status 141 when you use pipes

tr -dc 'a-zA-Z0-9' < /dev/urandom | fold -w 20 | head -1

Solution 7:[7]

Using sparse array to shuffle characters.

#!/bin/bash

array=()
for i in {a..z} {A..Z} {0..9}; do
    array[$RANDOM]=$i
done
printf %s ${array[@]::8} $'\n'

(Or alot of random strings)

#!/bin/bash

b=()
while ((${#b[@]} <= 32768)); do
    a=(); for i in {a..z} {A..Z} {0..9}; do a[$RANDOM]=$i; done; b+=(${a[@]})
done
tr -d  ' ' <<< ${b[@]} | fold -w 8 | head -n 4096

Solution 8:[8]

Little bit obscure but short to write solution is

RANDSTR=$(mktemp XXXXX) && rm "$RANDSTR"

expecting you have write access to current directory ;-) mktemp is part of coreutils

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 ATo
Solution 4
Solution 5 done
Solution 6 Radu Gabriel
Solution 7
Solution 8 dosmanak