Bashシェルスクリプトでランダムな数値(乱数)を生成する

2022-03-09Bash,CentOS,Linux,Ubuntu,Zsh

はじめに

意外にも、初歩的な「乱数」に関するエントリを書いたことがなかった( 過去にサラリと触れていぐらいた )ようなので、今回ネタにすることにしました。

「ランダム」というキーワードを取り上げたエントリも参考に紹介します。

検証環境

$ uname -moi
x86_64 x86_64 GNU/Linux

$ head -n 2 /etc/os-release
NAME="Ubuntu"
VERSION="21.04 (Hirsute Hippo)"

$ bash -version | head -n 1
GNU bash, バージョン 5.1.4(1)-release (x86_64-pc-linux-gnu)

乱数を取得するための組み込み変数「RANDOM」を使う

Bashには、乱数を取得するための組み込み変数として RANDOM というものが用意されています。

試しに $RANDOM を出力してみましょう。

$ echo $RANDOM
458

$ echo $RANDOM
11854

echo $RANDOM を実行するたびに、出力される数値が異なります。

"RANDOM" 変数の最大値は?最小値は?

RANDOM 変数は参照するたびにランダムな値を返しますが、値の範囲はどうなっているでしょうか?

試しに $RANDOM を 1,000,000回 出力した結果を集計してみます。

# 1,000,000回 ループして、 RANDOM 変数を参照する。
# 結果を ソート → 重複除去 してファイルに書き出す。
$ for i in {0..1000000}; do echo ${RANDOM}; done | sort -n | uniq > result.txt

# ファイルの行数は 32,768 行
$ wc -l result.txt
32768 result.txt

# 先頭5行を確認
$ head -n 5 result.txt
0
1
2
3
4

# 末尾5行を確認
$ tail -n 5 result.txt
32763
32764
32765
32766
32767

このように、 "RANDOM" 変数は 0 〜 32767 の間でランダムな数値を返却します

( 2の15乗分の数値がランダムに算出されます。 )

# 2の15乗 を算出
$ echo $((2**15))
32768

任意の範囲の乱数を求める方法( ex: 0〜5 )

任意の範囲の乱数を求めたい場合にはどうしたらよいでしょう?

例えば、 サイコロの出目として6つの数値( 0〜5 )をランダムに取得したい場合 はどうしたら良いでしょう?

この場合も RANDOM 変数を利用することができます。

# $RAMDOM % 出目の数 を算出する
$ echo $((RANDOM % 6))
1

$ echo $((RANDOM % 6))
3

10,000回 出力した結果を集計してみます。

# 10,000回 0〜5 までの数値を出力し、、数を数える
$ for i in {0..10000}; do echo $((RANDOM % 6)); done | sort -n | uniq -c > result2.txt

# 0〜5 の数値がそれぞれ、おおよそ 1667回 出力されている
$ cat result2.txt
   1690 0
   1669 1
   1701 2
   1620 3
   1669 4
   1652 5

コインの出目を求めたい場合には 2で割ったあまり を算出します。

$ echo $((RANDOM % 2))
0

$ echo $((RANDOM % 2))
0

$ echo $((RANDOM % 2))
1

"32767" 以上の乱数を算出したい場合は?

"32767" 以上の乱数を求めたい場合にはどうしたら良いでしょう?

shuf コマンドを使うのが確実です。

shuf コマンドを使って 「1から100,000」 までの乱数を算出してみます。

$ shuf -i 1-100000 -n 1
92326

$ shuf -i 1-100000 -n 1
8180

$ shuf -i 1-100000 -n 1
28623

shuf コマンドがない場合は?

shuf コマンドがない場合は、以下のように seqsorthead を組み合わせて頑張りましょう。

# sort -R で標準入力をランダムに入れ替える
$ seq 1 100000 | sort -R | head -n 1
89938

$ seq 1 100000 | sort -R | head -n 1
11193

$ seq 1 100000 | sort -R | head -n 1
4539

ただ、複数コマンドを組み合わせていることもあり、 遅い です。

ひとこと

使えるなら RANDOM で実現するのがよいでしょう。

2022-03-09Bash,CentOS,Linux,Ubuntu,Zsh