繁体   English   中英

在 Bash 中使用“$RANDOM”生成随机字符串

[英]Using "$RANDOM" to generate a random string in Bash

我正在尝试使用 Bash 变量$RANDOM创建一个随机字符串,该字符串由来自包含 integer 和字母数字的变量的 8 个字符组成,例如var="abcd1234ABCD"

我怎样才能做到这一点?

使用参数扩展。 ${#chars}是可能的字符数, %是模运算符。 ${chars:offset:length}选择位置offset的字符,即在我们的例子中为 0 - length($chars)。

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

对于那些在 bash 中寻找随机字母数字字符串的人:

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

与有据可查的函数相同:

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
}

另一种生成 32 字节(例如)十六进制字符串的方法:

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

如果您想要大写字符,请添加-u

选项 1 - 没有特定长度,不需要 openssl,只有字母和数字,比选项 2

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

演示: 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 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

例子:

j0PYAlRI1r8zIoOSyBhh9MTtrhcI6d
nrCaiO35BWWQvHE66PjMLGVJPkZ6GBK
0WUHqiXgxLq0V0mBw2d7uafhZt2s
c1KyNeznHltcRrudYpLtDZIc1
edIUBRfttFHVM6Ru7h73StzDnG

选项 2 - 没有特定长度,需要openssl ,只有字母和数字,比选项 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.

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

例子:

9FbVwZZRQeZSARCH
9f8869EVaUS2jA7Y
V5TJ541atfSQQwNI
V7tgXaVzmBhciXxS

不使用$RANDOM ,但值得一提。

使用 shuf 作为熵源(又名随机性)(反过来,可以使用/dev/random作为熵源。如 `shuf -i1-10 --random-source=/dev/urandom)似乎是一个解决方案使用更少的资源:

$ shuf -er -n8  {A..Z} {a..z} {0..9} | paste -sd ""
tf8ZDZ4U
head -1 <(fold -w 20  <(tr -dc 'a-zA-Z0-9' < /dev/urandom))

如果您打开了安全选项,这在 bash 脚本中使用是安全的:

set -eou pipefail

这是使用管道时 bash 退出状态 141 的解决方法

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

使用稀疏数组来打乱字符。

#!/bin/bash

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

(或很多随机字符串)

#!/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

有点晦涩但写起来很短的解决方案是

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

期望您对当前目录具有写入权限;-) mktemp是 coreutils 的一部分

更新:正如 Bazi 在评论中指出的那样,可以在不创建文件的情况下使用 mktemp ;-) 所以命令可以更短。

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

使用trdd

chars='abcd1234ABCD'
length='8'
tr -cd "$chars" </dev/urandom | dd bs=1 count="$length" 2>/dev/null
echo

基于Radu Gabriel 的回答并使用 GNU bash 版本 4.4.20 测试并set -euxo pipefail的缩写安全 pipe 解决方法:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM