Shell 下如何生成随机数呢,米扑博客特意写了本文,总结 Linux Shell 产生随机数的多种方法。
本文原文转自米扑博客:Linux Shell 生成随机数和随机字符串
计算机产生的的只是“伪随机数”,不会产生绝对的随机数(是一种理想随机数)。实际上,伪随机数和理想随机数也是相对的概念,例如伪随机数在1万万亿亿亿年内也无法重复,算是理想随机数么?
伪随机数在大量重现时也并不一定保持唯一,但一个好的伪随机产生算法将可以产生一个非常长的不重复的序列,例如 UUID(通用唯一识别码)在100亿年内才可用完。
1. 使用系统的 $RANDOM 变量(CentOS、Ubuntu、MacOS 都支持,但只有5位数随机)
mimvp@ubuntu:~$ echo $RANDOM 17617
$RANDOM 的范围是 [0, 32767]
**示例:**使用 for 循环来验证:
#!/bin/bash # mimvp.com 2016.05.10
function print_random() { for i in {1…10}; do echo -e “$i \t $RANDOM” done }
print_random
运行结果:
# sh mimvp_shell_rand.sh 1 20191 2 16817 3 25971 4 1489 5 34 6 25183 7 920 8 315 9 18845 10 29519
如需要生成超过32767的随机数,可以用以下方法实现(有缺陷)
例:生成 40,000,000~50,000,000 的随机数,但最后末尾五位数在随机变化,实现原理有缺陷
#!/bin/bash # mimvp.com 2016.05.10
## Linux 系统随机数 + 范围上限值后, 再取余 function mimvp_random_bignum() { min=$1 max= 2 m i d = 2 m i d = 2 m i d = 2mid=2mid= 2 mid= 2mid=2mid=2mid=(mimvp_randnum_openssl4000000050000000)echo−e"i \t $randnum" done }
print_randnum_openssl
运行结果:
# sh mimvp_shell_rand.sh 1 43422505 2 40756492 3 45087076 4 43882168 5 47105153 6 45505018 7 41411938 8 48662626 9 47508094 10 41362566
6. 自定义数组生成随机数
自定义一个数组,用于生成一段特定长度(整数最长为18位)的有数字和字母组成的字符串,字符串中元素取自自定义的池子。
array=(0 1 2 3 4 5 6 7 8 9) # 自定义一个数字数组
num=${#array[*]} # 获取数组的长度(元素个数)
randnum=KaTeX parse error: Expected 'EOF', got '}' at position 30: …ror: Expected '}̲', got '\[' at …((RANDOM%num))]} # 利用Linux系统默认的 $RANDOM 随机数,随机从数组选择一个元素,构成新的长度数组
**示例:**自定义数组生成 40,000,000~50,000,000 之间的随机数(注释有点不好看,但非常有助于理解代码哈)
#!/bin/bash # mimvp.com 2016.05.10
## 6. custom array, 可以生成整数, 字符串 function mimvp_randnum_array() { NUM_LENGTH=18 # 整数的位数, 依据取值范围设定, 默认最长为18位整数(取决于正整数的范围) STR_ARRAY=(0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) # 生成字符串 STR_ARRAY=(0 1 2 3 4 5 6 7 8 9) # 生成整数
str\_array\_count=${#STR_ARRAY\[@\]} # 字符串数组的元素个数, 62 = 10 + 26 + 26
# echo “str_array_count: ${str_array_count}”
i=1
while \[ "$i" -le "${NUM_LENGTH}" \];
do
randnum\_array\[$i\]=${STR\_ARRAY\[$((RANDOM%str\_array\_count))\]}
let "i=i+1"
done
randnum\_array\_count=${#randnum_array\[@\]}
# echo “randnum_array_count: ${randnum_array_count}” # NUM_LENGTH 的长度: 18 # echo “randnum_array: ${randnum_array[@]}” # 打印出全部数组元素, 如 B 2 y t z K c Z s N l 9 T b V w j 6
num='1' # 整数首位不能是0, 因此直接固定为1, 防止整数时首位为0的异常错误
for item in ${randnum_array\[@\]};
do
num="${num}${item}"
done
# echo “num: $num” # 1B2ytzKcZsNl9TbVwj6
min=$1
max=$2
mid=$(($max-$min+1))
randnum=$(($num%$mid+$min))
echo $randnum
}
function print_randnum_array() { for i in {1…10}; do randnum=KaTeX parse error: Expected 'EOF', got '&' at position 44: …50000000)echo−e&̲quot;(mimvp_ran…nummid+$min))
# 排除的端口号 1080, 4500, 8080, 58866, 可以任意添加
port_exclude='1080,4500,8080,58866'
flag=\`echo ${port_exclude} | grep ${randnum} | wc -l\`
while \[ "$flag" -eq "1" \]
do
num=$(head -n 20 /dev/urandom | cksum | cut -f1 -d ' ')
randnum=$(($num%$mid+$min))
flag=\`echo ${port_exclude} | grep ${randnum} | wc -l\`
done
echo $randnum
}
function print_app_port() { for i in {1…10}; do randnum=KaTeX parse error: Expected 'EOF', got '&' at position 32: …02565535)echo−e&̲quot;(mimvp_app…(mimvp_app_port102565535)echo−e"i \t $randnum" done }
print_app_port
运行结果:
# sh mimvp_shell_rand.sh
1 29483 2 61738 3 31935 4 3242 5 19865 6 56677 7 5944 8 28579 9 12510 10 31844
随机数应用二
随机生成长度为10的密码字符串 (通用于 CentOS, Ubuntu, MacOS)
应用的随机数是 方法1:使用系统的 $RANDOM 变量
应用代码:
#!/bin/bash # mimvp.com 2016.05.10
## 应用二: 随机生成长度为10的密码字符串 (通用于 CentOS, Ubuntu, MacOS) function mimvp_app_passwd() { user_array=`seq -w 10` echo ${user_array[@]}
for idx in ${user_array\[@\]}
do
user_name="user-${idx}"
passwd=\`echo $RANDOM | md5sum | cut -c11-20\`
echo -e "${user_name} \\t ${passwd}"
done
}
mimvp_app_passwd
运行结果:
# sh mimvp_shell_rand.sh
01 02 03 04 05 06 07 08 09 10 user-01 52cf5272cb user-02 40f20d352d user-03 9fe9a7b770 user-04 ff4e20e6e0 user-05 88fc4a3ea3 user-06 6494032261 user-07 6a42732519 user-08 6fc7a25dd5 user-09 f0b6a95608 user-10 49219467fa
随机数应用三
统计掷骰子,投掷6000次统计分别为1-6的次数 (通用于 CentOS, Ubuntu, MacOS)
应用的随机数是 方法1:使用系统的 $RANDOM 变量
应用代码:
#!/bin/bash # mimvp.com 2016.05.10
## 应用三: 统计掷骰子, 投掷6000次统计分别为1-6的次数 (通用于 CentOS, Ubuntu, MacOS) function mimvp_app_dice() { MAX=6000 stat_1=0 stat_2=0 stat_3=0 stat_4=0 stat_5=0 stat_6=0
i=1
while \[ "$i" -le "$MAX" \]
do
randnum=$(($RANDOM%6)) # 对6取余, 余数为0时记作6点
case "$randnum" in
0) stat\_6=\`expr ${stat\_6} + 1\`;; # 余数为0时记作6点
1) stat\_1=\`expr ${stat\_1} + 1\`;;
2) stat\_2=\`expr ${stat\_2} + 1\`;;
3) stat\_3=\`expr ${stat\_3} + 1\`;;
4) stat\_4=\`expr ${stat\_4} + 1\`;;
5) stat\_5=\`expr ${stat\_5} + 1\`;;
esac
let "i=i+1"
done
echo “stat_1 ${stat_1}”
echo “stat_2 ${stat_2}”
echo “stat_3 ${stat_3}”
echo “stat_4 ${stat_4}”
echo “stat_5 ${stat_5}”
echo “stat_6 ${stat_6}”
}
mimvp_app_dice
运行结果:
# sh mimvp_shell_rand.sh
stat_1 923 stat_2 994 stat_3 977 stat_4 1039 stat_5 1072 stat_6 995
总结
random、urandom、uuid、openssl rand、自定义数组(用到了 $RANDOM)产生随机码的伪数据来源,都与 /dev/random 设备有关系,只是它们各自呈现不同。
date 日期生成的随机数,与Linux 系统的随机设备 /dev/random 的关系不大,但系统时间也会影响 /dev/random 设备,两者并非绝对无关系。
所有可以生成随机整数的方法,都可以生成随机字符串,原理是对随机整数进行 md5sum 计算
最后,附上完整的 shell 代码,方便爱好者研究、调试
#!/bin/bash # mimvp.com 2016.05.10
## 1. Linux 系统默认随机数 function print_randnum() { for i in {1…10}; do randnum=KaTeX parse error: Expected 'EOF', got '#' at position 41: …ed 'EOF', got '#̲' at position 8…(awk ‘BEGIN{srand(); print rand()*1000000; }’) # awk 随机种子函数, 最多5位随机数, 跟时间有关 echo -e “$i \t $randnum” done }
## Linux 系统随机数 + 范围上限值后, 再取余 function mimvp_randnum_bignum() { min=$1 max= 2 m i d = 2 m i d = 2 m i d = 2mid=2mid= 2 mid= 2mid=2mid=2mid=(mimvp_randnum_openssl4000000050000000)echo−e"i \t $randnum" done }
## 6. custom array, 可以生成整数, 字符串 function mimvp_randnum_array() { NUM_LENGTH=18 # 整数的位数, 依据取值范围设定, 默认最长为18位整数(取决于正整数的范围) STR_ARRAY=(0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z) # 生成字符串 STR_ARRAY=(0 1 2 3 4 5 6 7 8 9) # 生成整数
str\_array\_count=${#STR_ARRAY\[@\]} # 字符串数组的元素个数, 62 = 10 + 26 + 26
# echo “str_array_count: ${str_array_count}”
i=1
randnum_array=()
while \[ "$i" -le "${NUM_LENGTH}" \];
do
randnum\_array\[$i\]=${STR\_ARRAY\[$((RANDOM%str\_array\_count))\]}
let "i=i+1"
done
randnum\_array\_count=${#randnum_array\[@\]}
# echo “randnum_array_count: ${randnum_array_count}” # NUM_LENGTH 的长度: 18 # echo “randnum_array: ${randnum_array[@]}” # 打印出全部数组元素, 如 B 2 y t z K c Z s N l 9 T b V w j 6
num='1' # 整数首位不能是0, 因此直接固定为1, 防止整数时首位为0的异常错误
for item in ${randnum_array\[@\]};
do
num="${num}${item}"
done
# echo “num: $num” # 1B2ytzKcZsNl9TbVwj6
min=$1
max=$2
mid=$(($max-$min+1))
randnum=$(($num%$mid+$min))
echo $randnum
}
function print_randnum_array() { for i in {1…10}; do randnum=KaTeX parse error: Expected 'EOF', got '&' at position 44: …50000000)echo−e&̲quot;(mimvp_ran…nummid+$min))
# 排除的端口号 1080, 4500, 8080, 58866, 可以任意添加
port_exclude='1080,4500,8080,58866'
flag=\`echo ${port_exclude} | grep ${randnum} | wc -l\`
while \[ "$flag" -eq "1" \]
do
num=$(head -n 20 /dev/urandom | cksum | cut -f1 -d ' ')
randnum=$(($num%$mid+$min))
flag=\`echo ${port_exclude} | grep ${randnum} | wc -l\`
done
echo $randnum
}
function print_app_port() { for i in {1…10}; do randnum=KaTeX parse error: Expected 'EOF', got '&' at position 32: …02565535)echo−e&̲quot;(mimvp_app…