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

如果没有大小限制,PORT=$(($RANDOM%63000+2001))将很好地工作。

有没有人有一个例子,我可以这样做,也许从/dev/urandom提取一些东西,并得到它在一个范围内?


当前回答

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

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

因为你的范围不是2的幂,一个简单的模运算几乎只能给你一个均匀的分布,但如果输入范围是30位,输出范围小于16位,就像你的例子一样,这应该足够接近了:

PORT=$(( ((RANDOM<<15)|RANDOM) % 63001 + 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

它会读取两个字节,并将它们作为unsigned int输出;你还是得剪。

生成范围为[$floor,$ceil]的随机数,不依赖:

$(((RANDOM % $(($ceil- $floor))) + $floor))

在2000到65000之间生成100个数字:

for i in $(seq 100); do echo $(((RANDOM % $((65000 - 2000))) + 2000));done
shuf -i 2000-65000 -n 1

享受吧!

编辑:范围是包括在内的。

这对我来说很管用:

export CUDA_VISIBLE_DEVICES=$((( RANDOM % 8 )))

如果你想让它从1开始而不是0,你可以加1。

$RANDOM是0到32767之间的数字。您希望端口在2000到65000之间。这有63001个可能的端口。如果我们坚持在2000到33500之间使用$RANDOM + 2000的值,我们将覆盖31501个端口。如果我们抛硬币,然后有条件地在结果中加上31501,我们可以得到更多的端口,从33501到65001。然后,如果我们只删除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
}

测试

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