Reputation: 429
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
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
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
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
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
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
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
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
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
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
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