2000-65000
シェルスクリプトからランダムなポート番号を生成する必要があります。問題は$RANDOM
15ビットの数値なので、行き詰まっています!
PORT=$(($RANDOM%63000+2001))
サイズの制限がなければ、うまく機能します。
誰かが私がこれを行う方法の例を持っていますか、おそらく/dev/urandom
範囲から何かを抽出してそれを取得することによって?
2000-65000
シェルスクリプトからランダムなポート番号を生成する必要があります。問題は$RANDOM
15ビットの数値なので、行き詰まっています!
PORT=$(($RANDOM%63000+2001))
サイズの制限がなければ、うまく機能します。
誰かが私がこれを行う方法の例を持っていますか、おそらく/dev/urandom
範囲から何かを抽出してそれを取得することによって?
回答:
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%の改善が見られ、100万回の反復で約4秒の差がありました。そして、それはだたくさん速くOPのバッシュ計算万回を実行するよりも。
-n 1
も、時間差はごくわずかend=4000000000
です。知っておくとshuf
Mac OS XおよびFreeBSDでは、jotを使用することもできます。
jot -r 1 2000 65000
jot
は、間隔の最小値と最大値(つまり、2000と65000)が不公平に分布しています。つまり、最小値と最大値が生成される頻度が低くなります。詳細と回避策については、私の回答を参照してください。
jot
ほとんどのGNU / Linuxディストリビューションでも利用可能
bashのmanページによると、0〜32767の$RANDOM
範囲で配布されています。つまり、符号なし15ビット値です。$RANDOM
均一に分散されていると仮定すると、次のように均一に分散された符号なし30ビット整数を作成できます。
$(((RANDOM<<15)|RANDOM))
あなたの範囲は2の累乗ではないので、単純なモジュロ演算はほぼ均一な分布を与えるだけですが、あなたの場合のように、30ビットの入力範囲と16ビット未満の出力範囲があります、これは本当に十分に近いはずです:
PORT=$(( ((RANDOM<<15)|RANDOM) % 63001 + 2000 ))
$RANDOM
はすべてのシェルで常に使用できるわけではありません。別の解決策を探している
$RANDOM
2回参照することに注意してください。をサポートするシェル$RANDOM
では、参照されるたびに新しい値が生成されます。したがって、このコードはビット0から14を1つの$RANDOM
値で埋め、ビット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
保証されません
-S
オプションを使用すると、になりますImportError: No module named random
。削除すれば動作します。そのためのゴーストドッグの意図がわからない。
python -S -c "import random; print random.randrange(2000,63000)"
正常に動作するようです。しかし、1と2の間の乱数を取得しようとすると、常に1を取得するようです。
頭に浮かぶ最も簡単な一般的な方法は、perlのワンライナーです。
perl -e 'print int(rand(65000-2000)) + 2000'
常に2つの数値を使用できます。
PORT=$(($RANDOM + ($RANDOM % 2) * 32768))
あなたはまだあなたの範囲にクリップする必要があります。これは一般的なnビットの乱数メソッドではありませんが、あなたのケースで機能し、すべてbash内にあります。
本当にかわいくて/ dev / urandomから読みたい場合は、次のようにします。
od -A n -N 2 -t u2 /dev/urandom
これは2バイトを読み取り、それらをunsigned 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 Script Random Number Generatorを参照してください。
Bashのドキュメントでは、$RANDOM
参照されるたびに0〜32767の乱数が返されると記載されています。2つの連続した参照を合計すると、0〜65534の値が得られます。これは、2000〜65000の乱数の63001の可能性の望ましい範囲をカバーします。
これを正確な範囲に調整するには、63001を法とする合計を使用します。これにより、0〜63000の値が得られます。これは、2000から65000の範囲の目的の乱数を提供するために、2000だけ増分する必要があります。これは、次のように要約されます。
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
ごとに変更されることになっているので、2による乗算にそれをリファクタリングしないでください。サムバージョンで答えを更新しました。
RANDOM+RANDOM
あなたを与えることはありません均一 0と65534の間で乱数の分布を
またはOS-Xでは次のように動作します:
$ gsort --random-sort
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
は比較的最近のことだと思います-この2、3年はUbuntuシステムで見ましたが、現在のRHEL / CentOSでは見ていません。