Bash 生成随机内容

2018-11-30 language bash

在编写代码时,一般会使用伪随机函数,不过对于安全通讯往往存在风险,Linux 提供了随机生成设备,可以提供基本满足真随机内容。

这里介绍常见的使用技巧。

简介

在 Linux 的 /dev/ 目录下存在两个相关的随机数发生器 randomurandom,后者也就是 unblocked random,两个特殊的设备文件中产生,会利用系统熵池计算出一定数量的随机比特,然后将这些比特作为字节流返回。

熵池就是当前系统的环境噪音,可以通过很多参数来评估,如内存、文件的使用、不同类型的进程数量等等。

两者区别

如果当前环境噪音变化的不是很剧烈或者当前环境噪音很小,比如刚开机的时候,而当前需要大量的随机比特,这时产生的随机数的随机效果就不是很好了。

这也就是上述两个文件的区别,前者不能产生新的随机数时会阻塞,直到根据熵池产生新的随机字节之后才返回;而后者不会阻塞,只是此时产生的可能是伪随机数,对加密解密这样的应用来说就不是一种很好的选择。

所以使用 /dev/random 比使用 /dev/urandom 产生大量随机数的速度要慢。

$ dd if=/dev/random of=random.dat bs=1024b count=1
0+1 records in
0+1 records out
128 bytes (128 B) copied, 0.000169 seconds, 757 kB/s

$ dd if=/dev/urandom of=random.dat bs=1024b count=1
1+0 records in
1+0 records out
524288 bytes (524 kB) copied, 0.091297 seconds, 5.7 MB/s

相比来说,前者在内核中熵不足时会阻塞,而后者则不会,详细可以查看 Myths about /dev/urandom

常用命令

可以通过命令行直接读取字符串的内容,从而生成随机的字符串,如下的命令中,其中 C 表示生成的字符串的字符数,L 表示要生成多少行随机字符。

----- 生成全字符随机的字串
$ cat /dev/urandom | strings -n C | head -n L

----- 生成数字加字母的随机字串
$ cat /dev/urandom | sed 's/[^a-zA-Z0-9]//g' | strings -n C | head -n L

----- 也可以直接通过Base64转换
$ head -c 32 /dev/random | base64

注意,如上的方式中会存在换行符,只有在出现长度是 C 的字符串时才打印,会导致打印速度很慢;所以,最好是通过如下方式生成,然后手动截取。

$ cat /dev/urandom | sed 's/[^a-zA-Z0-9]//g' | strings | tr -d '\n\r'

如果要生成随机整数,可以通过 shell 中的一个环境变量 RANDOM,它的范围是 0~32767

----- 生成 [0, 25] 的随机数
$ echo $(($RANDOM%26))

----- 生成 [6, 100] 的随机数
$ echo $(($RANDOM%95+6))

参考