我需要2000-65000
从shell脚本之间生成一个随机端口号。问题是$RANDOM
15位数字,所以我卡住了!
PORT=$(($RANDOM%63000+2001))
如果没有大小限制,它将很好地工作。
有没有人举例说明我如何做到这一点,也许是通过从中提取某些东西/dev/urandom
并使其处于一定范围内?
我需要2000-65000
从shell脚本之间生成一个随机端口号。问题是$RANDOM
15位数字,所以我卡住了!
PORT=$(($RANDOM%63000+2001))
如果没有大小限制,它将很好地工作。
有没有人举例说明我如何做到这一点,也许是通过从中提取某些东西/dev/urandom
并使其处于一定范围内?
Answers:
shuf -i 2000-65000 -n 1
请享用!
编辑:范围包括在内。
shuf
确实会置换整个输入。如果您经常生成随机数,那么这将是一个错误的选择。
time for i in {1..1000}; do shuf -i 0-$end -n 1000 > /dev/null; done
并进行比较end=1
,end=65535
结果显示较短范围的距离提高了约25%,在一百万次迭代中相差约4秒。而且它的很多不是执行OP的计算猛砸一百万倍的速度。
-n 1
即使使用,运行时的时间差异也可以忽略不计end=4000000000
。众所周知,shuf
工作很聪明,但并不难:-)
在Mac OS X和FreeBSD上,您也可以使用jot:
jot -r 1 2000 65000
jot
间隔的最大值和最小值(即2000和65000)具有不公平的分布。换句话说,最小值和最大值将不太频繁地生成。有关详细信息和解决方法,请参见我的简要答案。
jot
在大多数GNU / Linux发行版中也可用
根据bash手册页,$RANDOM
分布在0到32767之间;也就是说,它是一个无符号的15位值。假设$RANDOM
是均匀分布的,则可以如下创建一个均匀分布的无符号30位整数:
$(((RANDOM<<15)|RANDOM))
由于您的范围不是2的幂,因此简单的模运算几乎几乎可以为您提供均匀的分布,但是具有30位的输入范围和小于16位的输出范围(如您的情况),这确实应该足够接近:
PORT=$(( ((RANDOM<<15)|RANDOM) % 63001 + 2000 ))
$RANDOM
并非总是在所有shell中都可用。寻找其他解决方案
$RANDOM
两次。在支持的shell上$RANDOM
,每次引用它都会生成一个新值。因此,此代码用一个$RANDOM
值填充位0到14,并用另一个值填充位15到29。假设$RANDOM
是统一且独立的,那么它会覆盖从0到2 ** 30-1的所有值,而不会跳过任何内容。
这是Python的
randport=$(python -S -c "import random; print random.randrange(2000,63000)")
和一个与awk
awk 'BEGIN{srand();print int(rand()*(63000-2000))+2000 }'
RANDOM
POSIX无法保证,
-S
选项将导致ImportError: No module named random
。如果我删除它的作品。不确定ghostdog的意图是什么。
python -S -c "import random; print random.randrange(2000,63000)"
似乎工作正常。但是,当我尝试获得1到2之间的随机数时,我似乎总是得到1...。
想到的最简单的通用方法是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
这将读取两个字节并将它们打印为一个无符号的int;您仍然需要剪裁。
awk
另一个答案的版本
$RANDOM
是0到32767之间的数字。您需要2000到65000之间的端口。这是63001个可能的端口。如果我们将值保持$RANDOM + 2000
在2000到33500之间,则可以覆盖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
你可以这样做
cat /dev/urandom|od -N2 -An -i|awk -v f=2000 -v r=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))
测试中
# 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
计算的正确性
这是一个完整的蛮力测试,用于确定计算的正确性。该程序只是使用被测计算尝试随机生成所有63001种不同的可能性。该--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
为了确定要获得p/q
所有63001种可能性的给定概率,需要进行多少次迭代,我相信我们可以使用以下表达式。例如,这里为概率大于1/2的计算,和这里为大于9/10。
$RANDOM
是一个整数。使用您的“技巧”,将有许多永远无法实现的价值。-1
。
$RANDOM
,并且不要将其重构为乘以2,因为$RANDOM
应该在每次访问中进行更改。我已经用总和版本更新了答案。
RANDOM+RANDOM
不会给你一个统一的随机数的0和65534之间的分配
PORT=$(($RANDOM%63000+2001))
接近我想要的。
PORT=$(($RANDOM$RANDOM$RANDOM%63000+2001))
避开困扰您的尺寸限制。由于bash在数字变量和字符串变量之间没有区别,因此效果很好。$RANDOM
可以像字符串一样将“数字” 串联起来,然后在计算中用作数字。惊人!
x=$(( $n%63000 )
大致类似于x=$(( $n % 65535 )); if [ $x -gt 63000 ]; then x=63000
。
这就是我通常生成随机数的方式。然后,将“ 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
shuf
是相对较新的-在过去的几年中,我已经在Ubuntu系统上看到了它,但是当前的RHEL / CentOS却没有。