Bashの範囲内で乱数を生成する方法は?
$RANDOM
を使用します。多くの場合、単純なシェル演算と組み合わせて使用すると便利です。たとえば、1〜10の乱数を生成するには:
$ echo $((1 + RANDOM % 10))
3
実際のジェネレーターはvariables.c
、関数brand()
にあります。 旧バージョン は単純な線形ジェネレーターでした。 bash
のバージョン4.0では、1985年の論文で 引用付きのジェネレーター を使用しています。シミュレーションには使用しません(もちろん暗号化にも使用しません)が、基本的なスクリプト作成タスクにはおそらく十分でしょう。
深刻な乱数を必要とすることをしている場合は、/dev/random
または/dev/urandom
を使用できます(使用可能な場合)。
$ dd if=/dev/urandom count=4 bs=1 | od -t d
$RANDOM
を参照してください:
$RANDOM
は、0〜32767の範囲の擬似乱数整数を返す(定数ではなく)内部Bash関数です。暗号化キーの生成には使用しないでください。
シェルからこれを試してください:
$ od -A n -t d -N 1 /dev/urandom
ここで、-t d
は、出力形式が符号付き10進数であることを指定します。 -N 1
は、/dev/urandom
から1バイトを読み取るように指示します。
shuf(coreutilsで使用可能)も使用できます。
shuf -i 1-100000 -n 1
また、awkから乱数を取得することもできます
awk 'BEGIN {
# seed
srand()
for (i=1;i<=1000;i++){
print int(1 + Rand() * 100)
}
}'
$ RANDOMがあります。どのように機能するのか正確にはわかりません。しかし、それは機能します。テストのために、次のことができます。
echo $RANDOM
0から9までの乱数。
echo $((RANDOM%10))
私はこのトリックが好きです:
echo ${RANDOM:0:1} # random number between 1 and 9
echo ${RANDOM:0:2} # random number between 1 and 99
...
Linuxシステムを使用している場合は、 / dev/random or /dev/urandomから乱数を取得できます。十分な乱数が利用できない場合、/ dev/randomがブロックすることに注意してください。ランダム性よりも高速が必要な場合は、/ dev/urandomを使用します。
これらの「ファイル」には、オペレーティングシステムによって生成された乱数が格納されます。真または擬似乱数を取得する場合、システム上の/ dev/randomの実装に依存します。真の乱数は、マウス、ハードドライブ、ネットワークなどのデバイスドライバーから収集されたノイズを形成するのに役立ちます。
dd でファイルから乱数を取得できます
/ dev/randomまたは/ dev/urandomの文字特殊ファイルから読み取る方法があります。
これらのデバイスは、読み取られたときに真に乱数を返し、アプリケーションソフトウェアが暗号化用の安全なキーを選択できるように設計されています。このような乱数は、さまざまなランダムイベントによって提供されるエントロピープールから抽出されます。 {LDD3、ジョナサン・コーベット、アレッサンドロ・ルビニ、グレッグ・クローア・ハートマン]
これらの2つのファイルは、カーネルのランダム化、特に
void get_random_bytes_Arch(void* buf, int nbytes)
そのような機能が実装されたハードウェアによるものである場合(通常はそうである場合)、ハードウェアから真にランダムなバイトを引き出します。
dd if=/dev/urandom count=4 bs=1 | od -t d
これは機能しますが、dd
から不要な出力をstdoutに書き込みます。以下のコマンドは、必要な整数のみを提供します。算術展開に与えられたビットマスクを調整することで、必要に応じて指定された数のランダムビットを取得することもできます。
me@mymachine:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump
-d tmp | head -n 1 | cut -c13-15) && echo $(( 10#$x & 127 ))
これらのアイデアのいくつかを取り入れて、大量の乱数が必要な場合に迅速に実行される機能を作成しました。
od
の呼び出しは、大量の乱数が必要な場合には費用がかかります。代わりに、1回呼び出して、/ dev/urandomから1024個の乱数を保存します。 Rand
が呼び出されると、最後の乱数が返され、スケーリングされます。その後、キャッシュから削除されます。キャッシュが空の場合、さらに1024個の乱数が読み取られます。
例:
Rand 10; echo $RET
0から9までのRETの乱数を返します。
declare -ia RANDCACHE
declare -i RET RAWRAND=$(( (1<<32)-1 ))
function Rand(){ # pick a random number from 0 to N-1. Max N is 2^32
local -i N=$1
[[ ${#RANDCACHE[*]} -eq 0 ]] && { RANDCACHE=( $(od -An -tu4 -N1024 /dev/urandom) ); } # refill cache
RET=$(( (RANDCACHE[-1]*N+1)/RAWRAND )) # pull last random number and scale
unset RANDCACHE[${#RANDCACHE[*]}-1] # pop read random number
};
# test by generating a lot of random numbers, then effectively place them in bins and count how many are in each bin.
declare -i c; declare -ia BIN
for (( c=0; c<100000; c++ )); do
Rand 10
BIN[RET]+=1 # add to bin to check distribution
done
for (( c=0; c<10; c++ )); do
printf "%d %d\n" $c ${BIN[c]}
done
更新:それはすべてのNでそれほどうまく機能しません。小さなNで使用すると、ランダムビットも無駄になります。 9 = 1,000,000,000 <= 2 * 32)32個のランダムソース値から複数の乱数を抽出できます。
#!/bin/bash
declare -ia RCACHE
declare -i RET # return value
declare -i ENT=2 # keep track of unused entropy as 2^(entropy)
declare -i RND=RANDOM%ENT # a store for unused entropy - start with 1 bit
declare -i BYTES=4 # size of unsigned random bytes returned by od
declare -i BITS=8*BYTES # size of random data returned by od in bits
declare -i CACHE=16 # number of random numbers to cache
declare -i MAX=2**BITS # quantum of entropy per cached random number
declare -i c
function Rand(){ # pick a random number from 0 to 2^BITS-1
[[ ${#RCACHE[*]} -eq 0 ]] && { RCACHE=( $(od -An -tu$BYTES -N$CACHE /dev/urandom) ); } # refill cache - could use /dev/random if CACHE is small
RET=${RCACHE[-1]} # pull last random number and scale
unset RCACHE[${#RCACHE[*]}-1] # pop read random number
};
function randBetween(){
local -i N=$1
[[ ENT -lt N ]] && { # not enough entropy to supply ln(N)/ln(2) bits
Rand; RND=RET # get more random bits
ENT=MAX # reset entropy
}
RET=RND%N # random number to return
RND=RND/N # remaining randomness
ENT=ENT/N # remaining entropy
};
declare -ia BIN
for (( c=0; c<100000; c++ )); do
randBetween 10
BIN[RET]+=1
done
for c in ${BIN[*]}; do
echo $c
done
どうですか:
Perl -e 'print int Rand 10, "\n"; '
少し遅すぎるかもしれませんが、jot
を使用してBashの範囲内で乱数を生成するのはどうでしょうか。
jot -r -p 3 1 0 1
これにより、小数点以下3桁の精度(-r
)でランダム(-p
)番号が生成されます。この特定のケースでは、0〜1の間の1つの数字(1 0 1
)を取得します。順次データを印刷することもできます。マニュアルによると、乱数のソースは次のとおりです。
乱数は、シードが指定されていない場合はarc4random(3)を介して取得され、シードが指定されている場合はrandom(3)を介して取得されます。
0からn(符号付き16ビット整数)の範囲の乱数を生成します。 $ Rand変数の結果セット。例えば:
#!/bin/bash
random()
{
local range=${1:-1}
Rand=`od -t uI -N 4 /dev/urandom | awk '{print $2}'`
let "Rand=$Rand%($range+1)"
}
n=10
while [ $(( n -=1 )) -ge "0" ]; do
random 500
echo "$Rand"
done