Dimareal
Dimareal

Reputation: 429

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?

Upvotes: 29

Views: 44467

Answers (10)

aimass
aimass

Reputation: 418

Doesn't use $RANDOM but if you have /dev/random you could do this and it's compatible with bash and other shells such as plain Bourne:

pwd=$(dd status=noxfer if=/dev/random bs=1 count=7 2>/dev/null | hexdump -C | grep -E -o '[a-z0-9A-Z]' | tr -d '\n' | tr -d '0')

Upvotes: 0

insign
insign

Reputation: 5783

OPTION 1 - Specific length, only lowercase letters, numbers and dashes

cat /proc/sys/kernel/random/uuid OR on macOS just use uuidgen

After generating 1 billion UUIDs every second for the next 100 years, the probability of creating just one duplicate would be about 50%. The probability of one duplicate would be about 50% if every person on earth owns 600 million UUIDs 😇 source

DEMO: x=100; while [ $x -gt 0 ]; do cat /proc/sys/kernel/random/uuid; x=$(($x-1)); done

Examples:

be821d3c-c484-41d9-8fc8-eb8bc3683360
ba0b72e2-7969-481e-94c2-7a716c40c3e8
e0183127-a6e3-453b-87cd-7ea912afc49a
0ad84c92-186a-4c4d-aea9-5951083c9ed8
a42e0c6a-4f06-4c32-a289-dd0391f11aba
a82b27d4-9bdb-403d-add4-8a72d36fb864
a16fcd29-02cd-448a-a048-ae6bde3c707c

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

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

OR on macOS:

sed "s/[^a-zA-Z0-9]//g" <<< $(head -c 24 /dev/urandom | base64 | tr -dc '[:print:]' | 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 3 - No specific length, openssl needed, only letters and numbers (if used with sed), faster than option 2

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

Upvotes: 14

Michael McMahon
Michael McMahon

Reputation: 33

An abbreviated safe pipe workaround based on Radu Gabriel's answer and tested with GNU bash version 4.4.20 and set -euxo pipefail:

head -c 20 <(tr -dc [:alnum:] < /dev/urandom)

Upvotes: 2

dosmanak
dosmanak

Reputation: 506

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

UPDATE: As Bazi pointed out in the comment, mktemp can be used without creating the file ;-) so the command can be even shorter.

RANDSTR=$(mktemp --dry-run XXXXX)

Upvotes: 3

Denis Ryzhkov
Denis Ryzhkov

Reputation: 2609

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
}

Upvotes: 24

user8017719
user8017719

Reputation:

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

Upvotes: 8

Radu Gabriel
Radu Gabriel

Reputation: 3201

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

Upvotes: 5

ATo
ATo

Reputation: 290

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.

Upvotes: 13

user12007102
user12007102

Reputation:

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

Upvotes: 3

choroba
choroba

Reputation: 241858

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

Upvotes: 27

Related Questions