在Bash脚本中的范围内的随机数

我需要从shell脚本生成一个2000-65000之间的随机端口号。 问题是$RANDOM是一个15位数字,所以我卡住了!

PORT=$(($RANDOM%63000+2001))如果不是用于大小限制,将会很好地工作。

有没有人有我如何能做到这一点的例子,也许从/dev/urandom提取一些东西,并在一个范围内?

 shuf -i 2000-65000 -n 1 

请享用!

编辑 :范围是包容性的。

在Mac OS X和FreeBSD上,您也可以使用jot:

 jot -r 1 2000 65000 

根据bash手册页, $RANDOM分布在0和32767之间; 也就是说,它是一个无符号的15位值。 假设$RANDOM是均匀分布的,您可以创build一个均匀分布的无符号30位整数,如下所示:

 $(((RANDOM<<15)|RANDOM)) 

由于你的范围不是2的乘方,所以一个简单的模运算几乎只能给你一个统一的分布,但是如你的情况那样,一个30位的input范围和一个小于16位的输出范围,这应该真的够接近了:

 PORT=$(( ((RANDOM<<15)|RANDOM) % 63001 + 2000 )) 

这里是Python的一个

 randport=$(python -S -c "import random; print random.randrange(2000,63000)") 

和一个awk

 awk 'BEGIN{srand();print int(rand()*(63000-2000))+2000 }' 

想到的最简单的一般方法是perl单行程:

 perl -e 'print int(rand(65000-2000)) + 2000' 

你总是可以使用两个数字:

 PORT=$(($RANDOM + ($RANDOM % 2) * 32768)) 

你仍然必须剪辑到你的范围。 这不是一个通用的n位随机数字方法,但它适用于你的情况,而且都在bash中。

如果你想变得非常可爱并且从/ dev / urandom中读取,你可以这样做:

 od -A n -N 2 -t u2 /dev/urandom 

这将读取两个字节,并将其打印为无符号整数; 你仍然必须做你的裁剪。

$RANDOM是一个0到32767之间的数字。你想要一个介于2000到65000之间的端口。它们是63001个可能的端口。 如果我们坚持200033500之间$RANDOM + 2000值,我们覆盖了31501个端口的范围。 如果我们翻转一个硬币,然后有条件地添加31501的结果,我们可以得到更多的端口,从3350165001 。 那么如果我们只是下降65001,我们就得到了所需要的确切覆盖面,似乎所有港口的统一概率分布。

 random-port() { while [[ not != found ]]; do # 2000..33500 port=$((RANDOM + 2000)) while [[ $port -gt 33500 ]]; do port=$((RANDOM + 2000)) done # 2000..65001 [[ $((RANDOM % 2)) = 0 ]] && port=$((port + 31501)) # 2000..65000 [[ $port = 65001 ]] && continue echo $port break done } 

testing

 i=0 while true; do i=$((i + 1)) printf "\rIteration $i..." printf "%05d\n" $(random-port) >> ports.txt done # Then later we check the distribution sort ports.txt | uniq -c | sort -r 

如果你不是一个bash专家,并希望在基于Linux的bash脚本中获得这个variables,试试这个:

VAR=$(shuf -i 200-700 -n 1)

这可以让你将200到700的范围变成$VAR (含)。

这是另一个。 我认为它可以处理任何事情,但sorting的随机选项不工作在我的工作箱上。

  seq 2000 65000 | sort -R | head -n 1 

你可以这样做

cat /dev/urandom|od -N2 -An -i|awk -vf=2000 -vr=65000 '{printf "%i\n", f + r * $1 / 65536}'

如果您需要更多的细节,请参阅Shell脚本随机数生成器 。

Bash文档说每次引用$RANDOM ,都会返回0到32767之间的一个随机数。 如果我们总结两个连续的引用,我们得到0到65534之间的值,它涵盖了2000到65000之间随机数的63001个可能的范围。

为了将其调整到确切的范围,我们使用模数63001,这将给我们一个从0到63000的值。这反过来只需要2000的增量来提供2000到65000之间的所需的随机数。这可以是总结如下:

 port=$((((RANDOM + RANDOM) % 63001) + 2000)) 

testing

 # Generate random numbers and print the lowest and greatest found test-random-max-min() { max=2000 min=65000 for i in {1..10000}; do port=$((((RANDOM + RANDOM) % 63001) + 2000)) echo -en "\r$port" [[ "$port" -gt "$max" ]] && max="$port" [[ "$port" -lt "$min" ]] && min="$port" done echo -e "\rMax: $max, min: $min" } # Sample output # Max: 64990, min: 2002 # Max: 65000, min: 2004 # Max: 64970, min: 2000 

计算的正确性

这是一个完整的蛮力testing的计算正确性。 该程序试图随机生成所有63001个不同的可能性,使用被testing的计算。 --jobs参数应该使其运行得更快,但不是确定性的(生成的可能性总数可能低于63001)。

 test-all() { start=$(date +%s) find_start=$(date +%s) total=0; ports=(); i=0 rm -f ports/ports.* ports.* mkdir -p ports while [[ "$total" -lt "$2" && "$all_found" != "yes" ]]; do port=$((((RANDOM + RANDOM) % 63001) + 2000)); i=$((i+1)) if [[ -z "${ports[port]}" ]]; then ports["$port"]="$port" total=$((total + 1)) if [[ $((total % 1000)) == 0 ]]; then echo -en "Elapsed time: $(($(date +%s) - find_start))s \t" echo -e "Found: $port \t\t Total: $total\tIteration: $i" find_start=$(date +%s) fi fi done all_found="yes" echo "Job $1 finished after $i iterations in $(($(date +%s) - start))s." out="ports.$1.txt" [[ "$1" != "0" ]] && out="ports/$out" echo "${ports[@]}" > "$out" } say-total() { generated_ports=$(cat "$@" | tr ' ' '\n' | \sed -E s/'^([0-9]{4})$'/'0\1'/) echo "Total generated: $(echo "$generated_ports" | sort | uniq | wc -l)." } total-single() { say-total "ports.0.txt"; } total-jobs() { say-total "ports/"*; } all_found="no" [[ "$1" != "--jobs" ]] && test-all 0 63001 && total-single && exit for i in {1..1000}; do test-all "$i" 40000 & sleep 1; done && wait && total-jobs 

为了确定需要多less次迭代来获得所有63001个可能性的给定概率p/q ,我相信我们可以使用下面的expression式。 例如, 这里是大于1/2的概率的计算 , 这里是 大于9/10 。

表达

或者在OS-X上,以下对我有用:

 $ gsort --random-sort 

PORT=$(($RANDOM%63000+2001))接近你想要的我想的。

PORT=$(($RANDOM$RANDOM$RANDOM%63000+2001))解决了麻烦的大小限制。 由于bash没有区分数字variables和stringvariables,所以这个工作非常好。 “number” $RANDOM可以像string一样连接,然后在计算中用作数字。 惊人!

与ruby一样:

 ZZZ=$(ruby -e 'puts rand(20..65)') echo $ZZZ #=> 56 

你可以通过随机获得随机数

head -200 /dev/urandom | cksum

输出:

3310670062 52870

检索上述编号的一部分。

head -200 /dev/urandom | cksum | cut -f1 -d " "

那么输出是

3310670062

为了满足您的要求,

head -200 /dev/urandom |cksum | cut -f1 -d " " | awk '{print $1%63000+2001}'

这是我通常如何产生随机数字。 然后我使用“NUM_1”作为我使用的端口号的variables。 这是一个简短的示例脚本。

 #!/bin/bash clear echo 'Choose how many digits you want for port# (1-5)' read PORT NUM_1="$(tr -dc '1-65000' </dev/urandom | head -c $PORT)" echo "$NUM_1" if [ "$PORT" -gt "5" ] then clear echo -e "\x1b[31m Choose a number between 1 and 5! \x1b[0m" sleep 3 clear exit 0 fi