如何在Bash中生成随机数?

如何在Bash中生成一个范围内的随机数?

380897 次浏览

请参见$RANDOM:

$RANDOM是Bash内部函数 (不是常量)返回 范围内的伪随机整数 0 - 32767。它不应该被用来

.生成加密密钥

有$RANDOM。 我不知道具体是怎么回事。但它确实有效。 对于测试,您可以执行:

echo $RANDOM

如果你使用的是linux系统,你可以从/dev/random或 /dev/ urrandom中得到一个随机数。注意,如果没有足够的随机数可用,/dev/random将阻塞。如果你需要速度超过随机性,请使用/dev/ urrandom。

这些“文件”将由操作系统生成的随机数填充。如果你得到的是真随机数还是伪随机数,这取决于系统上/dev/random的实现。真正的随机数是在从鼠标、硬盘、网络等设备驱动程序收集噪声的帮助下生成的。

你可以用dd从文件中获取随机数

使用$RANDOM。它通常与简单的shell算法结合使用很有用。例如,要生成1到10(包括)之间的随机数:

$ echo $((1 + $RANDOM % 10))
3

实际的生成器在variables.c中,函数brand()旧版本是一个简单的线性发生器。bash的4.0版本使用了一个带有引文的生成器到1985年的论文,这大概意味着它是一个不错的伪随机数来源。我不会将它用于模拟(当然也不会用于加密),但它可能足以用于基本的脚本任务。

如果你正在做一些需要严重随机数的事情,你可以使用/dev/random/dev/urandom(如果它们可用的话):

$ dd if=/dev/urandom count=4 bs=1 | od -t d

也可以从awk中获取随机数

awk 'BEGIN {
# seed
srand()
for (i=1;i<=1000;i++){
print int(1 + rand() * 100)
}
}'

试试你的shell:

$ od -A n -t d -N 1 /dev/urandom

这里,-t d指定输出格式应该是带符号的十进制;-N 1表示从/dev/urandom中读取一个字节。

生成0到n范围内的随机数(有符号的16位整数)。$RAND变量中的结果集。例如:

#!/bin/bash


random()
{
local range=${1:-1}


RAND=`od -t uI -N 4 /dev/urandom | awk '{print $2}'`
let "RAND=$RAND%($range+1)"
}


n=10
while [ $(( n -=1 )) -ge "0" ]; do
random 500
echo "$RAND"
done

0到9之间的随机数。

echo $((RANDOM%10))

我已经采取了一些这些想法,并做出了一个函数,应该执行迅速,如果大量的随机数是必需的。

如果你需要大量的随机数,调用od是昂贵的。相反,我只调用它一次,并存储来自/dev/urandom的1024个随机数。当调用rand时,返回最后一个随机数并按比例缩放。然后从缓存中删除它。当缓存为空时,再读取1024个随机数。

例子:

rand 10; echo $RET

返回RET中0到9(含9)之间的随机数。

declare -ia RANDCACHE
declare -i RET RAWRAND=$(( (1<<32)-1 ))


function rand(){  # pick a random number from 0 to N-1. Max N is 2^32
local -i N=$1
[[ ${#RANDCACHE[*]} -eq 0 ]] && { RANDCACHE=( $(od -An -tu4 -N1024 /dev/urandom) ); }  # refill cache
RET=$(( (RANDCACHE[-1]*N+1)/RAWRAND ))  # pull last random number and scale
unset RANDCACHE[${#RANDCACHE[*]}-1]     # pop read random number
};


# test by generating a lot of random numbers, then effectively place them in bins and count how many are in each bin.


declare -i c; declare -ia BIN


for (( c=0; c<100000; c++ )); do
rand 10
BIN[RET]+=1  # add to bin to check distribution
done


for (( c=0; c<10; c++ )); do
printf "%d %d\n" $c ${BIN[c]}
done

更新:这并不适用于所有n。如果使用小n,也会浪费随机位。注意(在这种情况下)一个32位随机数有足够的熵用于0到9之间的9个随机数(10*9=1,000,000,000 <= 2*32),我们可以从每个32个随机源值中提取多个随机数。

#!/bin/bash


declare -ia RCACHE


declare -i RET             # return value
declare -i ENT=2           # keep track of unused entropy as 2^(entropy)
declare -i RND=RANDOM%ENT  # a store for unused entropy - start with 1 bit


declare -i BYTES=4         # size of unsigned random bytes returned by od
declare -i BITS=8*BYTES    # size of random data returned by od in bits
declare -i CACHE=16        # number of random numbers to cache
declare -i MAX=2**BITS     # quantum of entropy per cached random number
declare -i c


function rand(){  # pick a random number from 0 to 2^BITS-1
[[ ${#RCACHE[*]} -eq 0 ]] && { RCACHE=( $(od -An -tu$BYTES -N$CACHE /dev/urandom) ); }  # refill cache - could use /dev/random if CACHE is small
RET=${RCACHE[-1]}              # pull last random number and scale
unset RCACHE[${#RCACHE[*]}-1]  # pop read random number
};


function randBetween(){
local -i N=$1
[[ ENT -lt N ]] && {  # not enough entropy to supply ln(N)/ln(2) bits
rand; RND=RET       # get more random bits
ENT=MAX             # reset entropy
}
RET=RND%N  # random number to return
RND=RND/N  # remaining randomness
ENT=ENT/N  # remaining entropy
};


declare -ia BIN


for (( c=0; c<100000; c++ )); do
randBetween 10
BIN[RET]+=1
done


for c in ${BIN[*]}; do
echo $c
done

是什么:

perl -e 'print int rand 10, "\n"; '

从/dev/random或/dev/urandom字符特殊文件读取是可行的方法。

这些设备在读取和设计时返回真正的随机数 帮助应用软件选择用于加密的安全密钥。这样的 随机数是从熵池中提取的 通过各种随机事件。{LDD3,乔纳森·科贝,亚历山德罗

这两个文件是内核随机化的接口

void get_random_bytes_arch(void* buf, int nbytes)

它从硬件中抽取真正随机的字节,如果这样的功能是由硬件实现的(通常是),或者它从熵池中抽取(包括事件之间的时间,如鼠标和键盘中断,以及注册在SA_SAMPLE_RANDOM中的其他中断)。

dd if=/dev/urandom count=4 bs=1 | od -t d

这是有效的,但从dd写入不需要的输出到stdout。下面的命令给出了我需要的整数。我甚至可以得到指定的随机位数,因为我需要调整位掩码给算术展开:

me@mymachine:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump
-d tmp | head -n 1 | cut -c13-15) && echo $(( 10#$x & 127 ))

你也可以使用shuf(在coreutils中可用)。

shuf -i 1-100000 -n 1

我喜欢这个技巧:

echo ${RANDOM:0:1} # random number between 1 and 9
echo ${RANDOM:0:2} # random number between 1 and 99

...

也许我有点晚了,但是使用jot在Bash中生成一个范围内的随机数怎么样?

jot -r -p 3 1 0 1

这将生成一个随机的(-r)数字,具有3位小数精度(-p)。在这个特殊情况下,你将得到一个介于0和1之间的数字(1 0 1)。您还可以打印顺序数据。根据手册,随机数的来源为:

当没有指定种子时,通过arc4random(3)获得随机数,通过 当给出一个种子时,随机(3)

基于@Nelson, @Barun和@Robert的精彩回答,这里有一个生成随机数的Bash脚本。

  • 可以生成你想要的数字。
  • 每个数字分别由/dev/urandom生成,而不是Bash内置的$RANDOM
#!/usr/bin/env bash


digits=10


rand=$(od -A n -t d -N 2 /dev/urandom |tr -d ' ')
num=$((rand % 10))
while [ ${#num} -lt $digits ]; do
rand=$(od -A n -t d -N 1 /dev/urandom |tr -d ' ')
num="${num}$((rand % 10))"
done
echo $num

程序的随机分支或是/否;1/0;真/假输出:

if [ $RANDOM -gt 16383  ]; then              # 16383 = 32767/2
echo var=true/1/yes/go_hither
else
echo var=false/0/no/go_thither
fi

如果你懒得记16383年

if (( RANDOM % 2 )); then
echo "yes"
else
echo "no"
fi

bash 5.1引入了一个新变量SRANDOM,它从系统的熵引擎中获得随机数据,因此不是线性的,不能重新播种以获得相同的随机序列。这个变量可以代替RANDOM来生成更多的随机数字。

$ echo $((1 + SRANDOM % 10))
4

想在没有ddod的情况下使用/dev/urandom

function roll() { local modulus=${1:-6}; echo $(( 1 + 0x$(env LC_CTYPE=C tr -dc '0-9a-fA-F' < /dev/urandom | head -c5 ) % $modulus )); }

测试

$ roll
5
$ roll 12
12

它有多随机?

$ (echo "count roll percentage"; i=0; while [ $i -lt 10000 ]; do roll; i=$((i+1)); done | sort | uniq -c | awk '{print $0,($1/10000*100)"%"}') | column -t
count  roll  percentage
1625   1     16.25%
1665   2     16.65%
1646   3     16.46%
1720   4     17.2%
1694   5     16.94%
1650   6     16.5%

生成随机的3位数字

这对于创建示例数据非常有用。示例:将所有测试数据放在一个名为“test-create-volume-123”的目录中,然后在测试完成后,删除整个目录。通过生成恰好三个数字,你没有奇怪的排序问题

printf '%02d\n' $((1 + RANDOM % 100))

这是按比例缩小的,例如到一个数字:

printf '%01d\n' $((1 + RANDOM % 10))

它会放大,但是只有四位数字。原因见上文:)

一个bash函数,使用perl生成n位的随机数。指定数字数或n个0的模板。

rand() {
perl -E '$ARGV[0]||=""; $ARGV[0]=int($ARGV[0])||length($ARGV[0]); say join "", int(rand(9)+1)*($ARGV[0]?1:0), map { int(rand(10)) } (0..($ARGV[0]||0)-2)' $1
}

用法:

$ rand 3
381
$ rand 000
728

调用rand n的演示,n在0到15之间:

$ for n in {0..15}; do printf "%02d: %s\n" $n $(rand $n); done
00: 0
01: 3
02: 98
03: 139
04: 1712
05: 49296
06: 426697
07: 2431421
08: 82727795
09: 445682186
10: 6368501779
11: 51029574113
12: 602518591108
13: 5839716875073
14: 87572173490132
15: 546889624135868

演示调用rand n,对于n,一个长度在0到15之间的0模板

$ for n in {0..15}; do printf "%15s :%02d: %s\n" $(printf "%0${n}d" 0) $n $(rand $(printf "%0${n}d" 0)); done
0 :00: 0
0 :01: 0
00 :02: 70
000 :03: 201
0000 :04: 9751
00000 :05: 62237
000000 :06: 262860
0000000 :07: 1365194
00000000 :08: 83953419
000000000 :09: 838521776
0000000000 :10: 2355011586
00000000000 :11: 95040136057
000000000000 :12: 511889225898
0000000000000 :13: 7441263049018
00000000000000 :14: 11895209107156
000000000000000 :15: 863219624761093

我就此写了几篇文章。

$ RANDOM=$(date +%s%N | cut -b10-19)
$ echo $(( $RANDOM % 113 + 13 ))

上述将给出一个介于13到125(113-1+13)之间的数字,具有合理的随机熵。

你可以使用种子,参见文档:

RANDOM=$(date +%s%N | cut -b10-19)
echo $(( $RANDOM % 100 + 1 ))

这是我写的一个函数,它将输出一个期望范围内的随机数>

描述:

random <min> <max>

生成一个从minmax的随机数,包括。minmax都可以 正数或负数,生成的随机数也可以是负数,所以 只要范围(max - min + 1)小于或等于32767。Max必须是>= min。

它的核心是:

random() {
min="$1"
max="$2"
    

range=$((max - min + 1))
rand=$((min + (RANDOM % range)))
echo "$rand"
}

用法:

# general form: obtain a random number between min and max, inclusive
random <min> <max>


# Example: obtain a random number from -10 to 10, inclusive
random -10 10

这是从bash内置变量RANDOM中工作的,它可能只是在底层使用了C rand(),因为它们的最大值都是32767——请参阅:

  1. https://en.cppreference.com/w/c/numeric/random/rand
  2. https://en.cppreference.com/w/c/numeric/random/RAND_MAX

bash文档请参见man bash:

RANDOM

每次引用此参数时,将生成032767之间的随机整数。随机数序列可以通过赋值给RANDOM来初始化。如果RANDOMunset,它将失去其特殊属性,即使随后被重置。

健壮的,可运行的,sourceable版本的脚本

下面是上面random函数的一个更加健壮的版本。它包括完整的错误检查,边界检查,通过random --helprandom -h的帮助菜单,以及一个特殊的run_check功能,它允许你源或运行这个脚本,以便你可以source它来导入random函数到任何其他脚本中——就像你在Python中可以做的那样!

< >强random.sh < / >强 <——点击此链接总是从我的eRCaGuy_dotfiles回购中获得最新版本。

RETURN_CODE_SUCCESS=0
RETURN_CODE_ERROR=1


HELP_STR="\
Generate a random integer number according to the usage styles below.


USAGE STYLES:
'random'
Generate a random number from 0 to 32767, inclusive (same as bash variable 'RANDOM').
'random <max>'
Generate a random number from 0 to 'max', inclusive.
'random <min> <max>'
Generate a random number from 'min' to 'max', inclusive. Both 'min' and 'max' can be
positive OR negative numbers, and the generated random number can be negative too, so
long as the range (max - min + 1) is less than or equal to 32767. Max must be >= min.


This file is part of eRCaGuy_dotfiles: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles
"


print_help() {
echo "$HELP_STR" | less -RFX
}


# Get a random number according to the usage styles above.
# See also `utils_rand()` in utilities.c:
# https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/utilities.c#L176
random() {
# PARSE ARGUMENTS


# help menu
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
print_help
exit $RETURN_CODE_SUCCESS
fi


# 'random'
if [ $# -eq 0 ]; then
min=0
max="none"
# 'random max'
elif [ $# -eq 1 ]; then
min=0
max="$1"
# 'random min max'
elif [ $# -eq 2 ]; then
min="$1"
max="$2"
else
echo "ERROR: too many arguments."
exit "$RETURN_CODE_ERROR"
fi


# CHECK FOR ERRORS


if [ "$max" = "none" ]; then
rand="$RANDOM"
echo "$rand"
exit "$RETURN_CODE_SUCCESS"
fi


if [ "$max" -lt "$min" ]; then
echo "ERROR: max ($max) < min ($min). Max must be >= min."
exit "$RETURN_CODE_ERROR"
fi


# CALCULATE THE RANDOM NUMBER


# See `man bash` and search for `RANDOM`. This is a limitation of that value.
RAND_MAX=32767


range=$((max - min + 1))
if [ "$range" -gt "$RAND_MAX" ]; then
echo "ERROR: the range (max - min + 1) is too large. Max allowed = $RAND_MAX, but actual" \
"range = ($max - $min + 1) = $range."
exit "$RETURN_CODE_ERROR"
fi


# NB: `RANDOM` is a bash built-in variable. See `man bash`, and also here:
# https://stackoverflow.com/a/1195035/4561887
rand=$((min + (RANDOM % range)))
echo "$rand"
}


# Set the global variable `run` to "true" if the script is being **executed** (not sourced) and
# `main` should run, and set `run` to "false" otherwise. One might source this script but intend
# NOT to run it if they wanted to import functions from the script.
# See:
# 1. *****https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/bash/argument_parsing__3_advanced__gen_prog_template.sh
# 1. my answer: https://stackoverflow.com/a/70662049/4561887
# 1. https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/bash/check_if_sourced_or_executed.sh
run_check() {
# This is akin to `if __name__ == "__main__":` in Python.
if [ "${FUNCNAME[-1]}" == "main" ]; then
# This script is being EXECUTED, not sourced
run="true"
fi
}


# ----------------------------------------------------------------------------------------------------------------------
# Main program entry point
# ----------------------------------------------------------------------------------------------------------------------


# Only run main function if this file is being executed, NOT sourced.
run="false"
run_check
if [ "$run" == "true" ]; then
random "$@"
fi

不需要其他依赖项:

$(((RANDOM % $((upperBound - lowerBound))) + lowerBound))

随机数范围为[lowerBound,upperBound)

纯Bash随机数,没有

lowerRange=10   # inclusive
upperRange=20   # exclusive


randomNumber=$(( RANDOM * ( upperRange - lowerRange) / 32767 + lowerRange ))