特定の範囲の乱数を生成する


84

少しグーグルで調べた後、シェルコマンドを使用して特定の範囲(最小と最大の間)に含まれるランダムな10進整数を生成する簡単な方法を見つけることができませんでした。

/dev/random/dev/urandomおよびについて読みました$RANDOMが、これらはどれも必要なことを実行できません。

別の便利なコマンド、または以前のデータを使用する方法はありますか?


2
このSO Q&A:stackoverflow.com/questions/8988824/…およびこのstackoverflow.com/questions/2556190/…を参照してください。
slm


回答:


45

POSIXツールチェストでは、次を使用できますawk

awk -v min=5 -v max=10 'BEGIN{srand(); print int(min+rand()*(max-min+1))}'

これをソースとして使用してパスワードや秘密データを生成しないでください。ほとんどのawk実装では、コマンドが実行された時間に基づいて数字を簡単に推測できます。

多くのawk実装では、同じコマンドを同じ秒内に2回実行すると、一般に同じ出力が得られます。


1
+1 ..変数に出力を割り当てるスクリプトで使用される(改行文字を導入せず、2箇所にゼロパディングを使用しない):x=$(awk -v min=$min_var -v max=$max_var 'BEGIN{srand(); printf("%.2d", int(min+rand()*(max-min+1)))}')
Christopher

時間に基づいていますか?私は... 2回連続で同じ値を得たので
シャイアロン

@ShaiAlonは、現在の時刻がsrand()のデフォルトのシード値としてよく使用されるため、通常は時間に基づいています。それについてのStéphaneの回答を参照してください。を使用して、初期シードを乱数に変更することで回避できますawk -v min=5 -v max=10 -v seed="$(od -An -N4 -tu4 /dev/urandom)" 'BEGIN{srand(seed+0); print int(min+rand()*(max-min+1))}'$RANDOM代わりに使用することもできますod ... /dev/randomが、シード値は0から32767の比較的小さい範囲にあるため、時間の経過とともに出力に顕著な繰り返しが発生する可能性があります。
エドモートン

141

shufGNU coreutilsから試すことができます:

shuf -i 1-100 -n 1

これはBusyboxでも機能しますshuf
cov

raspbianとGitBashでも動作します。
nPcomp

30

ジョット

BSDやOSX上では使用することができますJOTを単一のランダム(戻るには-r間隔から)数をminするmax包括的、。

$ min=5
$ max=10
$ jot -r 1 $min $max

流通問題

残念ながら、ランダムに生成された数値の範囲と分布は、jotが内部的に倍精度浮動小数点演算を使用し、出力形式にprintf(3)を使用するという事実に影響されます。そのため、インターバルのはminmaxそれほど頻繁に実証されたように生成されます。

$ jot -r 100000 5 10 | sort -n | uniq -c
9918  5
20176 6
20006 7
20083 8
19879 9
9938  10

OS X 10.11(El Capitan)では、これは修正されたようです:

$ jot -r 100000 5 10 | sort -n | uniq -c
16692 5
16550 6
16856 7
16579 8
16714 9
16609 10  

そして...

$ jot -r 1000000 1 10 | sort -n | uniq -c
100430 1
99965 2
99982 3
99796 4
100444 5
99853 6
99835 7
100397 8
99588 9
99710 10

分布の問題を解決する

古いバージョンのOS Xの場合、幸いなことにいくつかの回避策があります。1つは、printf(3)整数変換を使用することです。唯一の注意点は、間隔の最大値がになったことmax+1です。整数のフォーマットを使用することにより、間隔全体に均等に分布します。

$ jot -w %i -r 100000 5 11 | sort -n | uniq -c
16756 5
16571 6
16744 7
16605 8
16683 9
16641 10

完璧なソリューション

最後に、回避策を使用してサイコロの公平なロールを取得するには、次のものがあります。

$ min=5
$ max_plus1=11  # 10 + 1
$ jot -w %i -r 1 $min $max_plus1

追加の宿題

血みどろの数学と書式設定の詳細およびその他の例については、jot (1)を参照してください。


15

この$RANDOM変数は通常、適切なランダム値を生成するのに適した方法ではありません。の出力/dev/[u]randomも最初に変換する必要があります。

より簡単な方法は、たとえばpythonのような高レベル言語を使用することです:

5〜10(5 <= N <= 10)の間のランダムな整数変数を生成するには、次を使用します。

python -c "import random; print random.randint(5,10)"

暗号化アプリケーションにはこれを使用しないでください。


これは役に立ちました。ありがとうございました:)多くの場合、署名済みはUnix-> Solaris 10で動作しますが、GNUユーティリティはデフォルトでは統合されていません。しかし、これはうまくいきました。
忍耐

11

乱数を取得できます urandom

head -200 /dev/urandom | cksum

出力:

3310670062 52870

上記の数値の一部を取得します。

head -200 /dev/urandom | cksum | cut -f1 -d " "

次に、出力は

3310670062


head -200(またはそのPOSIX同等物head -n 100)は、の最初の200 を返します/dev/urandom/dev/urandomテキストファイルではありません。このコマンドは200バイト(すべて0x0aの1、ASCIIのLF)から無限(0xaバイトが返されない場合)に戻る可能性がありますが、45k〜55kの値が最も可能性が高いです。cksumは32ビットの数値を返すため、から4バイト以上を取得しても意味がありません/dev/urandom
ステファンChazelas

7

5〜10(両方を含む)の間のランダムな整数変数を生成するには、次を使用します。

echo $(( RANDOM % (10 - 5 + 1 ) + 5 ))

% モジュロ演算子として機能します。

おそらく、ランダム変数$RANDOMを特定の範囲に変換するより良い方法があります。これを暗号化アプリケーションに使用したり、実際の等分布ランダム変数(シミュレーションなど)が必要な場合は使用しないでください。


3
$ RANDOMを持つ多くのシェル実装(特に古いもの、特にbash)では、これはあまりランダムではありません。ほとんどのシェルでは、数値は0〜65535であるため、幅が2の累乗ではない範囲には確率分布の不一致があります。(この場合、5から8までの数字は10923/65536の確率を持ち、9と10は10922/65536の確率を持ちます)。範囲が広いほど、差異が大きくなります。
ステファンシャゼル14

申し訳ありませんが、これは65535ではなく32767であるため、上記の計算は間違っています(実際にはさらに悪いことです)。
ステファンシャゼル14

私はより良い方法があることを書いたように@StéphaneChazelas私は、この点に注意していた...
jofel


4

おそらくUUID(Linuxの場合)を使用して乱数を取得できます

$ cat /proc/sys/kernel/random/uuid
cdd52826-327d-4355-9737-895f58ad11b4

70との間の乱数を取得するには100

POSIXLY_CORRECT=1 awk -F - '{print(("0x"$1) % 30 + 70)}
   ' /proc/sys/kernel/random/uuid


1

完全にbash内にとどまり、$ RANDOM変数を使用するが、不均一な分布を回避するには:

#!/bin/bash
range=10 
floor=20

if [ $range -gt 32768 ]; then
echo 'range outside of what $RANDOM can provide.' >&2
exit 1 # exit before entering infinite loop
fi 

max_RANDOM=$(( 2**15/$range*$range ))
r=$RANDOM
until [ $r -lt $max_RANDOM ]; do
r=$RANDOM
done
echo $(( r % $range + $floor ))

この例では、20〜29の乱数が提供されます。


$r[: -lt: unary operator expectedエラーを回避するには、65535または他の高い値に初期化する必要があります。
ローレンス

ループテスト前の$ r初期化を修正しました。ありがとう@LawrenceC!
エンジェルより

0

配布は良好です:

for((i = 1; i <= 100000; i ++))do echo $((RANDOM%(20-10 + 1)+ 10)); 完了| sort -n | uniq -c

カウント値

9183 10

9109 11

8915 12

9037 13

9100 14

9138 15

9125 16

9261 17

9088 18

8996 19

9048 20

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.