Jas*_*ner 177 bash shell scripting
我需要在2000-65000
shell脚本之间生成一个随机端口号.问题是$RANDOM
15位数,所以我卡住了!
PORT=$(($RANDOM%63000+2001))
如果不是因为尺寸限制,它会很好地工作.
有没有人有一个如何做到这一点的例子,可能是从/dev/urandom
一个范围内提取并得到它?
lee*_*777 362
shuf -i 2000-65000 -n 1
Run Code Online (Sandbox Code Playgroud)
请享用!
编辑:范围包含在内.
小智 76
在Mac OS X和FreeBSD上你也可以使用jot:
jot -r 1 2000 65000
Run Code Online (Sandbox Code Playgroud)
Jes*_*sin 39
根据bash手册页,$RANDOM
分布在0到32767之间; 也就是说,它是一个无符号的15位值.假设$RANDOM
均匀分布,您可以创建一个均匀分布的无符号30位整数,如下所示:
$(((RANDOM<<15)|RANDOM))
Run Code Online (Sandbox Code Playgroud)
由于你的范围不是2的幂,简单的模运算几乎只能给你一个均匀的分布,但是输入范围是30位,输出范围小于16位,就像你的情况一样,这应该足够接近:
PORT=$(( ((RANDOM<<15)|RANDOM) % 63001 + 2000 ))
Run Code Online (Sandbox Code Playgroud)
gho*_*g74 36
这是Python的一个
randport=$(python -S -c "import random; print random.randrange(2000,63000)")
Run Code Online (Sandbox Code Playgroud)
和一个与awk
awk 'BEGIN{srand();print int(rand()*(63000-2000))+2000 }'
Run Code Online (Sandbox Code Playgroud)
Cas*_*bel 15
想到的最简单的一般方法是perl one-liner:
perl -e 'print int(rand(65000-2000)) + 2000'
Run Code Online (Sandbox Code Playgroud)
你总是可以使用两个数字:
PORT=$(($RANDOM + ($RANDOM % 2) * 32768))
Run Code Online (Sandbox Code Playgroud)
你仍然需要剪辑到你的范围.它不是一般的n位随机数方法,但它适用于你的情况,而且它都在bash中.
如果你想要非常可爱并从/ dev/urandom中读取,你可以这样做:
od -A n -N 2 -t u2 /dev/urandom
Run Code Online (Sandbox Code Playgroud)
那将读取两个字节并将它们打印为unsigned int; 你仍然需要剪裁.
这是另一个.我认为它几乎可以用于任何事情,但是我的centos盒子里没有sort的随机选项.
seq 2000 65000 | sort -R | head -n 1
Run Code Online (Sandbox Code Playgroud)
小智 5
你可以这样做
cat /dev/urandom|od -N2 -An -i|awk -v f=2000 -v r=65000 '{printf "%i\n", f + r * $1 / 65536}'
Run Code Online (Sandbox Code Playgroud)
如果需要更多详细信息,请参阅Shell脚本随机数生成器.
小智 5
Bash 文档说,每次$RANDOM
引用时,都会返回 0 到 32767 之间的随机数。如果我们对两个连续引用求和,我们会得到从 0 到 65534 的值,这涵盖了 2000 到 65000 之间的随机数所需的 63001 种可能性范围。
为了将其调整到精确的范围,我们使用模 63001 求和,这将为我们提供一个从 0 到 63000 的值。反过来,只需增加 2000 即可提供所需的随机数,范围在 2000 到 65000 之间。这可以是总结如下:
port=$((((RANDOM + RANDOM) % 63001) + 2000))
Run Code Online (Sandbox Code Playgroud)
测试
# 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
Run Code Online (Sandbox Code Playgroud)
计算的正确性
这是对计算正确性的完整的强力测试。该程序只是尝试使用测试中的计算随机生成所有 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
Run Code Online (Sandbox Code Playgroud)
为了确定需要多少次迭代才能获得p/q
生成所有 63001 种可能性的给定概率,我相信我们可以使用下面的表达式。例如,这里是大于 1/2 的概率的计算,这里是大于 9/10 的概率的计算。
$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
}
Run Code Online (Sandbox Code Playgroud)
测试中
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
Run Code Online (Sandbox Code Playgroud)
如果您不是bash专家,并且希望将其转换为基于Linux的bash脚本中的变量,请尝试以下操作:
VAR=$(shuf -i 200-700 -n 1)
这将使您获得200到700的范围$VAR
,包括在内.
与红宝石相同:
echo $(ruby -e 'puts rand(20..65)') #=> 65 (inclusive ending)
echo $(ruby -e 'puts rand(20...65)') #=> 37 (exclusive ending)
Run Code Online (Sandbox Code Playgroud)