Bash脚本中某个范围内的随机数

Bash脚本中某个范围内的随机数,bash,shell,scripting,Bash,Shell,Scripting,我需要从shell脚本生成一个介于2000-65000之间的随机端口号。问题是,$RANDOM是一个15位的数字,所以我卡住了 PORT=$($RANDOM%63000+2001))如果没有大小限制,它会工作得很好 有没有人举个例子来说明我是如何做到这一点的,也许可以从/dev/uradom中提取一些东西,并将其放在一个范围内?想到的最简单的通用方法是perl一行程序: perl -e 'print int(rand(65000-2000)) + 2000' 您始终可以使用两个数字: PORT

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

PORT=$($RANDOM%63000+2001))
如果没有大小限制,它会工作得很好


有没有人举个例子来说明我是如何做到这一点的,也许可以从
/dev/uradom
中提取一些东西,并将其放在一个范围内?

想到的最简单的通用方法是perl一行程序:

perl -e 'print int(rand(65000-2000)) + 2000'
您始终可以使用两个数字:

PORT=$(($RANDOM + ($RANDOM % 2) * 32768))
你仍然需要根据自己的范围进行剪辑。这不是一个通用的n位随机数方法,但它适用于您的情况,并且都在bash中

如果您想变得非常可爱并阅读/dev/uradom,您可以这样做:

od -A n -N 2 -t u2 /dev/urandom
这将读取两个字节,并将它们打印为无符号整数;你还得做剪辑

shuf -i 2000-65000 -n 1
享受吧


编辑:范围是包含的。

这里有一个Python

randport=$(python -S -c "import random; print random.randrange(2000,63000)")
还有一个是awk

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

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

jot -r 1  2000 65000

这是另一个。我原以为它几乎可以在任何东西上工作,但sort的随机选项在我的centos机器上都不可用

 seq 2000 65000 | sort -R | head -n 1
你可以这样做

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

如果您需要更多详细信息,请参阅。

或在OS-X上,以下内容适用于我:

$ gsort --random-sort
export CUDA_VISIBLE_DEVICES=$((( RANDOM % 8 )))
PORT=$($RANDOM%63000+2001))
已经接近您想要的了

PORT=$($RANDOM$RANDOM$RANDOM%63000+2001))
绕过了困扰您的大小限制。因为bash对数字变量和字符串变量没有区别,所以它工作得非常好。“number”
$RANDOM
可以像字符串一样连接起来,然后在计算中用作数字。太棒了

每次引用
$RANDOM
时,都会返回一个介于0和32767之间的随机数。如果我们对两个连续的引用求和,我们会得到0到65534之间的值,这涵盖了2000到65000之间随机数的63001个可能的期望范围

为了将其调整到精确的范围,我们使用求和模63001,它将给我们一个从0到63000的值。这反过来只需要增加2000,以提供所需的随机数,介于2000和65000之间。这可以概括如下:

port=$((((RANDOM + RANDOM) % 63001) + 2000))
$(((RANDOM<<15)|RANDOM))
测试

# 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
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
计算的正确性

下面是一个完整的蛮力测试,以验证计算的正确性。该程序只是尝试使用测试中的计算,随机生成所有63001种不同的可能性。
--jobs
参数应使其运行更快,但它不是确定性的(生成的可能性总数可能低于63001)

为了确定需要多少次迭代才能获得生成的所有63001个可能性的给定概率
p/q
,我相信我们可以使用下面的表达式。例如,和


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

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

$(((RANDOM
$RANDOM
是一个介于0和32767之间的数字。您需要一个介于2000和65000之间的端口。这些是63001个可能的端口。如果我们坚持
$RANDOM+2000
介于200033500之间的值,我们覆盖了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
}
测试

# 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
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脚本中的变量中,请尝试以下方法:

VAR=$(shuf-i200-700-n1)


这将使您的范围从200到700,包括
$VAR

您可以通过
uradom

head-200/dev/uradom | cksum

输出:

3310670062 52870

检索上述编号的一部分

head-200/dev/uradom | cksum | cut-f1-d”“

然后输出为

3310670062

为了满足您的要求


head-200/dev/uradom | cksum | cut-f1-d“| awk'{print$1%63000+2001}”
这是我通常生成随机数的方式。然后我使用“NUM_1”作为我使用的端口号的变量。下面是一个简短的示例脚本

#!/bin/bash

clear
echo 'Choose how many digits you want for port# (1-5)'
read PORT

NUM_1="$(tr -dc '0-9' </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
!/bin/bash
清楚的
echo“选择端口#(1-5)所需的位数”
读取端口
NUM_1=“$(tr-dc'0-9'与ruby相同:

echo $(ruby -e 'puts rand(20..65)') #=> 65 (inclusive ending)
echo $(ruby -e 'puts rand(20...65)') #=> 37 (exclusive ending)
这对我很有用:

$ gsort --random-sort
export CUDA_VISIBLE_DEVICES=$((( RANDOM % 8 )))

如果希望从1开始而不是从0开始,可以添加1。

我认为
shuf
是相对较新的-我在过去几年在Ubuntu系统上见过它,但在当前的RHEL/CentOS上没有见过。同样,这种用法可能很好,但我相信
shuf
实际上会改变整个输入。如果你是非常频繁地生成随机数。@Dennis Williamson:使用
-n1
运行测试时,即使
end=4000000000
,时间差也可以忽略不计。很高兴知道
shuf
工作起来很聪明,不难:-)我的mac电脑上没有shuf:(@VirenShakya-如果您安装,那么您就可以
brew安装coreutils
。命令的安装前缀为
g
,因此它将是
gshuf
。我明白您的意思。我同意发行版会有所不同,但您无论如何都无法获得真正的随机性。有时使用$RANDOM,有时使用$RANDOM$RAN可能更好DOM,有时是$RANDOM$RANDOM$RANDOM,以获得更均匀的分布。据我所知,更多的$RANDOM有利于更高的端口号。(我删除了我的原始注释,因为我使用了一些错误的数字。)