在 Solaris 中生成随机数的最佳方法是什么?
我似乎无法为此找到一个好的答案。大多数结果在我的环境中不起作用。有一个变量或命令 RAND 看起来很合乎逻辑,它会以类似于 $RANDOM 的方式工作,我在大多数搜索中都看到它,但它总是产生 0。
我找到了这个命令
od -X -A n /dev/random | head -2
这看起来很随机,但返回格式很奇怪(对我来说)。
140774 147722 131645 061031 125411 053337 011722 165106
066120 073123 040613 143651 040740 056675 061051 015211
目前使用:
-bash-3.2$ uname -a
SunOS XXXXXXXXX 5.10 Generic_150400-29 sun4v sparc SUNW,SPARC-Enterprise-T5120
答案1
$RANDOM
在 ksh 和 bash 中可用,但在/bin/sh
.该值为 0 到 32768 之间的随机数,不适合加密使用。
读取/dev/random
会生成适合加密使用的随机字节流。由于这些是任意字节,可能包括空字节,因此您不能将它们存储在 shell 变量中。您可以将$n
字节存储在文件中
</dev/random dd ibs=1 count=$n >rnd
您可以od
使用八进制或十六进制值将这些字节转换为可打印的表示形式。如果您发现输出“奇怪”,那么,也许您应该选择不同的od
选项。
获取可打印表示的另一个选项是调用uuencode
生成 Base64:
</dev/random dd ibs=1 count=$n | uuencode -m _ | sed -e '1d' -e '$d'
答案2
这是获取字节(以十六进制数字n
表示)的三种方法:2*n
#!/bin/bash
n=64
# Read n bytes from urandom (in hex).
xxd -l "$n" -p /dev/urandom | tr -d " \n" ; echo
od -vN "$n" -An -tx1 /dev/urandom | tr -d " \n" ; echo
hexdump -vn "$n" -e ' /1 "%02x"' /dev/urandom ; echo
从 urandom 读取(请务必使用 urandom)。
十六进制数字可以重定向到文件或存储在变量中:
a="$(xxd -l "$n" -p /dev/urandom)"
您可以使用 xxd 获取原始字节,如下所示:
## 警告,这会产生二进制值
echo "$a" | xxd -r -p # If the Hex digits are in a variable.
xxd -r -p "$rndfile" # If the Hex digits are in a file.
如果 xxd 不可用,并假设十六进制数字位于$a
.
你可以使用这个 bash 代码:
#!/bin/bash
>"$rndfile" # erase the file
for (( i=0; i<${#a}/2; i++ )); do # do a loop over all byte values.
# convert 2 hex digits to the byte unsigned value:
printf '%b' $(printf '\\0%o' "0x${a:$i*2:2}") >> "$rndfile"
b="${b#??}" # chop out two hexadecimal digits.
done
或者您可以尝试这个 sh 兼容代码(应该可以在 bash 中轻松运行)。是的,它应该兼容 sh。如果发现问题请报告。
仅在破折号中进行了测试(但应该在其他一些中运行)。
#!/bin/sh
i=$((${#a}/2)) # The (length of $a ) / 2 is the number of bytes.
b="$a" # use a temporal variable. It will be erased.
: >"$rndfile" # erase file contents
while [ $i != 0 ]; do
# Write one byte transformed to binary:
printf '%b' $(printf '\\0%o' "0x${b%"${b#??}"}") >> "$rndfile"
b="${b#??}" # chop out two hexadecimal digits.
i=$((i-1)) # One byte less to finish.
done
答案3
</dev/random \
dd bs="${num_len}" count=1 | LC_ALL=C \
tr -c 0-9 "$(printf '[%d*24]' 9 8 7 6 5 4 3 2 1)[0*]"
尽管数字分布对于 0 来说非常有利,但对于以 10 为基数的情况应该可以很好地工作并且不会浪费任何东西。
对于 Solaris v<11,您将需要使用 ` 反引号而不是$(...)
命令替换。