Bashで乱数を生成する方法は?


236

Bashの範囲内で乱数を生成する方法は?


21
それはどれくらいランダムである必要がありますか?
bdonlan 2009

回答:


283

を使用し$RANDOMます。多くの場合、単純なシェル演算と組み合わせると便利です。たとえば、1〜10の乱数を生成するには、次のようにします。

$ echo $((1 + RANDOM % 10))
3

実際のジェネレータはvariables.c、関数内にありますbrand()古いバージョンは単純な線形ジェネレータでした。のバージョン4.0は、1985年の論文への引用付きbashジェネレーターを使用しています。これは、おそらく疑似乱数の適切なソースであることを意味します。シミュレーションには使用しません(もちろん暗号には使用しません)が、基本的なスクリプトタスクにはおそらく十分です。

あなたが使用できる深刻な乱数を必要とする何かをしている場合、/dev/randomまたは/dev/urandomそれらが利用可能な場合:

$ dd if=/dev/urandom count=4 bs=1 | od -t d

21
ここで注意してください。これはピンチで問題ありませんが、乱数で演算を行うと、結果のランダム性に劇的な影響を与える可能性があります。の場合$RANDOM % 10、8と9は$RANDOM、ランダムデータの強力なソースであっても、0から7よりも(わずかにではありますが)確率的に測定可能です。
dimo414 2014

3
@ dimo414私は「限界的に」に興味があります、これについてもっと知ることができるソースがありますか?
PascalVKooten 2014年

58
ランダム入力をモジュロ化することで、結果を「ハト穴」にします。以来$RANDOMの範囲は0-327670- 7へマップ3277異なる可能な入力が、89のみを製造することができる3276様々な方法(なぜなら3276832769は不可能です)。これはクイックハックのマイナーな問題ですが、結果が一様にランダムではないことを意味します。JavaのようなランダムライブラリRandomは、単に割り切れない数を変更するのではなく、指定された範囲の均一な乱数を適切に返す関数を提供します。
dimo414 2014年

1
@JFSebastianは非常に真実です-moduloの問題は、不良なPRNGだけでなく RNG の均一性を損なう可能性があることです。
dimo414 2014

14
単なる説明として、%10の基本的なピジョンホールは、8および9が0〜7よりも発生する可能性が約.03%少ないことを意味します。シェルスクリプトがそれよりも正確で均一な乱数を必要とする場合は、必ず、より複雑で適切なメカニズムを使用してください。
ネルソン

71

ご覧ください$RANDOM

$RANDOM 内部Bash関数(定数ではない)で、0〜32767の範囲の疑似乱数整数を返します。暗号化キーの生成には使用しないでください。


1
DOESは32767特別な意味を持っていますか?
ジンクォン

14
@JinKwon 327672^16 / 2 - 1、符号付き16ビット整数の上限です。
Jeffrey Martinez

@JinKwonなぜだと思いません2^15 - 1か?それは同等なので、私が見逃しているコンテキストがあるかどうかだけ知りたいですか?
ブレットホルマン2018

11
@BrettHolman彼は、符号付き16ビット整数の「符号付き」部分を指摘しようとしていたと思います。2 ^ 16値、正整数と負整数の場合は半分に分割。
cody、

この答えは質問には答えません。
ガキ

48

shuf(coreutilsで利用可能)を使用することもできます。

shuf -i 1-100000 -n 1

範囲の終わりとして変数をどのように渡しますか?私はこれを手に入れました:shuf -i 1-10 -n 1: syntax error in expression (error token is "1-10 -n 1")
dat tutbrus

1
追加$var:このように、代わりに範囲の最後のvar=100 && shuf -i 1-${var} -n 1
knipwim

2
でN個の乱数を生成するのは簡単なので、このオプションを選択します-n。例えば、1と100の間の5の乱数を生成しますshuf -i 1-100 -n 5
aerijman

私が理解している限り、数字はランダムではありません。指定shuf -i 1-10 -n 10すると、1から10までのすべての数値を取得します。指定した-n 15場合でも、これらの10個の数値のみが1回だけ取得されます。これは実際にシャッフルするだけで、乱数を生成しません。
ラドラン

置換で乱数を取得するには:-r
Geoffrey Anderson

36

シェルからこれを試してください:

$ od -A n -t d -N 1 /dev/urandom

ここで-t dは、出力形式が符号付き10進数であることを指定します。-N 1から1バイトを読み取るように言います/dev/urandom


2
質問は範囲内の数値を求めます。
JSycamore

9
あなたは、スペースを削除することができますod -A n -t d -N 1 /dev/urandom |tr -d ' '
ロバート・

23

awkから乱数を取得することもできます

awk 'BEGIN {
   # seed
   srand()
   for (i=1;i<=1000;i++){
     print int(1 + rand() * 100)
   }
}'

1
+1ご存知のように、最初はどうしてこのようにしたいのかと思いますが、実際にはとても気に入っています。
zelanix 2014年

1
シードを含むソリューションを提供してくれてありがとう。どこにも見つからなかった!
so.very.tired 2016

2
播種のための+1。srand()のシードは現在のCPU時間であることに言及する価値があるかもしれません。特定のシードを指定する必要があり、RNGを複製できるようにするsrand(x)場合xは、シードはwhereを使用します。また、GNU awkの数値関数のマニュアルからの引用によると、「内部で異なるawk実装は異なる乱数ジェネレータを使用しています」。要するに、統計的分布を生成することに関心がある場合は、異なるプラットフォーム(すべて実行中awkまたはgawk)で、あるランタイムから次のランタイムへのわずかな変動が予想されるはずです。
Cbhihe

18

$ RANDOMがあります。私はそれがどのように機能するか正確に知りません。しかし、それは機能します。テストのために、あなたは行うことができます:

echo $RANDOM

16

私はこのトリックが好きです:

echo ${RANDOM:0:1} # random number between 1 and 9
echo ${RANDOM:0:2} # random number between 1 and 99

...


7
$ RANDOMの範囲は0〜32767です。4〜9よりも、1、2、または3で始まる数値が多くなります。不均衡なディストリビューションで問題がなければ、これでうまくいきます。
jbo5112 2018

2
@ jbo5112あなたは完全に正しいです、最後の桁を表示するのはどうですか?1桁の場合は$ {RANDOM:0-1}をエコーし​​、2桁の場合は$ {RANDOM:0-2} ...をエコーし​​ます。
フラッフ

4
最後の桁を使用する場合、それはかなり良いですが、0と00が含まれます。1桁では、0〜7は8〜9よりも0.03%多く発生します。2桁では、0-67は68-99より0.3%頻繁に発生します。良い乱数分布が必要な場合は、bashを使用しないでください。オリジナルの場合:${RANDOM:0:1}1または2を与える可能性は67.8%で、1 ${RANDOM:0:2}桁の数字(1%である必要があります)を与える可能性は0.03%であり、どちらも0を与える可能性は0.003%です。 。これが問題とならないユースケースはまだあります(例:一貫性のない入力)。
jbo5112

12

0〜9の乱数。

echo $((RANDOM%10))

2
私の悪い、manページを正しく読みませんでした。$RANDOM0から32767までしかありません。「ランダムな数字は主に1から3の間で、いくつかのウィングがある」と言っているはずです;)
David Newcomb

1
何?別の回答で述べられているように、8と9は0から7に比べて発生する確率がわずかに低くなりますが、0から9の間です。
キニ

6

Linuxシステムを使用している場合は、/ dev / randomから乱数を取得できます。 / dev / urandom。十分な乱数が利用できない場合、/ dev / randomがブロックすることに注意してください。ランダム性よりも速度が必要な場合は、/ dev / urandomを使用してください。

これらの「ファイル」は、オペレーティングシステムによって生成された乱数で埋められます。真または疑似乱数を取得するかどうかは、システム上の/ dev / randomの実装に依存します。真の乱数は、マウス、ハードドライブ、ネットワークなどのデバイスドライバーから収集されたノイズを使用して生成されます。

あなたはddでファイルから乱数を得ることができます


5

私はこれらのアイデアのいくつかを取り入れ、たくさんの乱数が必要な場合にすばやく実行できる関数を作成しました。

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で使用すると、ランダムビットが無駄になります。(この場合)32ビットの乱数は、0から9までの9つの乱数に対して十分なエントロピーを持っています(10 * 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

私はこれを試しました-100%cpuの10秒がかかり、ランダムに見えない10個の数値を出力しました。
カルロウッド

今覚えています。このコードは100,000の乱数を生成します。それぞれを「ビン」に入れて、どれほどランダムかを調べます。10個のビンがあります。これらの数値は、0から9までの各乱数が等しく可能性が高い場合、類似しているはずです。あなたはそれぞれの番号を印刷したい場合は、RANDBETWEEN 10の後に$ RETエコー
philcolbourn

od -An -tu4 -N40 /dev/urandom空白で区切られた10個のランダムな符号なし32ビット整数を生成します。配列に格納して後で使用できます。あなたのコードはやり過ぎのようです。
Ali

@アリ、OPは彼らが32ビットも他のサイズの乱数も望んでいることを明言しなかった。私と他の何人かは、この質問を範囲内の乱数を提供すると解釈しました。私のrand関数はこの目標を達成し、使い果たされた場合にプログラムをブロックさせるエントロピーの損失も減らします。od on / dev / urandomは2 ^ Nビットの乱数のみを返すため、OPは複数の値を配列に格納し、この配列から値を順次抽出して、この配列を補充する必要があります。おそらくこれを答えとしてコーディングして、他の乱数範囲を処理できますか?
philcolbourn

@philcolbourn、あなたはOPが彼が望んでいるどのような種類の乱数を指定していないかについて正しく、それは私の注意を逃しました。しかし、彼はただ尋ねました:「bashで乱数を生成する方法?」。私のポイントは、彼は1つの乱数だけを要求したということです。この批評家は私の以前のコメント(10個の乱数を生成する)にも当てはまりますが。
Ali

5

/ 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 ))

3

何について:

perl -e 'print int rand 10, "\n"; '

1
暗号で保護された乱数の場合、/ dev / urandomから読み取るか、Crypt :: Randomライブラリを使用する必要があります。
KH

3

少し遅すぎるかもしれませんが、jotBashの範囲内で乱数を生成するために使用するのはどうですか?

jot -r -p 3 1 0 1

これにより、-r小数点以下3桁の精度(-p)の乱数()が生成されます。この特定のケースでは、0と1の間の1つの数値を取得します(1 0 1)。順次データを印刷することもできます。マニュアルによると、乱数のソースは次のとおりです。

乱数は、シードが指定されていない場合はarc4random(3)を介して取得され、シードが指定されている場合はrandom(3)を介して取得されます。


1
インストールする必要があります:sudo apt install athena-jot
xerostomus

3

@ Nelson、@ Barun、@ Robertのすばらしい回答に基づいて、乱数を生成するBashスクリプトを次に示します。

  • 必要な桁数を生成できます。
  • 各桁は別途によって生成さ/dev/urandomであるより良いバッシュのビルトインより$RANDOM
#!/usr/bin/env bash

digits=10

rand=$(od -A n -t d -N 2 /dev/urandom |tr -d ' ')
num=$((rand % 10))
while [ ${#num} -lt $digits ]; do
  rand=$(od -A n -t d -N 1 /dev/urandom |tr -d ' ')
  num="${num}$((rand % 10))"
done
echo $num

まさに私が求めていたもの。
プロメテウス

2

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

1

プログラムのランダム分岐またはyes / no; 1/0; 真/偽の出力:

if [ $RANDOM -gt 16383  ]; then              # 16383 = 32767/2 
    echo var=true/1/yes/go_hither
else 
    echo var=false/0/no/go_thither
fi

16383を覚えるのが面倒だとしたら:

if (( RANDOM % 2 )); then 
    echo "yes"
else 
    echo "no"
fi
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.