シェルスクリプトでランダムな文字列を生成したい
シェルスクリプトで任意の文字種と長さで構成されるランダムな文字列を生成する関数を作ってみます。
ランダムな文字列を作るには当然ランダム要素が必要になるので乱数を使います。今回は $RANDOM
をで乱数を作成します。シェルスクリプトで乱数を扱う方法は複数あるので乱数が作れれば何でもよいですので以下の記事を参考にしてください。
関数を定義するのが面倒やワンライナーで書きたいときに使えるコマンド例も最後にまとめます。
ランダムな文字列を生成する
早速実装です。
シェルスクリプトの関数
function get_random_string() {
# 以下の文字種からランダムに文字列を生成する
chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890'
chars_len=${#chars}
# 生成する文字数
len=16
if [ $(($1)) -gt 0 ]; then
len=$1
fi
# 生成する文字数だけループして乱数で文字を選ぶ
for i in `seq 1 $len`
do
pos=$(($RANDOM % $chars_len))
echo -n ${chars:$pos:1}
done
echo
}
第一引数で生成したい文字数を指定できるようにしています。もし不正な引数や引数の指定がない場合はデフォルトで16文字を生成する実装にしています。
関数の実装方針
- 使用可能な文字種(
chars
)を文字列で定義する。 - 生成する文字数(
len
)を定義する。 - 生成する文字数回(
len
)ループして以下の処理を実行する。- ランダムな整数(
$RANDOM
)を生成し、文字種類数で余りをとることで文字位置(pos
)を決める。 chars
のpos
番目の文字を生成結果の文字列に追加する。
- ランダムな整数(
- 得られたランダムな文字列を標準出力に書き出す
乱数を文字種類数で余りをとって、その位置に対応する文字種をランダムな文字列の結果の末尾に追加する処理を繰り返すイメージです。
- 文字列の長さの取得
- 部分文字列の取得
これが実装できればうまくいきそうです。
${#[変数名]} で文字列の長さを取得
変数に入った文字列の長さは ${#xxx}
とすることで取得可能です。
$ val='abc'
$ echo ${#val}
3
${[変数名]:[インデックス]:[長さ]} で部分文字列を取得
ランダムな文字列を構成する文字種類から一部を切り出すために、部分文字列を取得する処理を使用します。シェルスクリプトで部分文字列を取得するには以下のように指定します。
${[変数名]:[インデックス]:[長さ]}
インデックスはもちろんゼロインデックスで指定します。具体的には以下のように使用します。
$ val='abc'
$ echo ${val:0:1}
a
$ echo ${val:0:2}
ab
$ echo ${val:0:3}
abc
$ echo ${val:1:1}
b
$ echo ${val:1:2}
bc
$ echo ${val:2:1}
c
今回は chars
から pos
番目の1文字だけ切り出した値が欲しいので ${chars:$pos:1}
とします。
実装関数と使用例のまとめ
my_script.sh
#!/bin/bash
function get_random_string() {
# 以下の文字種からランダムに文字列を生成する
chars='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890'
chars_len=${#chars}
# 生成する文字数
len=16
if [ $(($1)) -gt 0 ]; then
len=$1
fi
# 生成する文字数だけループして乱数で文字を選ぶ
for i in `seq 1 $len`
do
pos=$(($RANDOM % $chars_len))
echo -n ${chars:$pos:1}
done
echo
}
# 文字数指定無しだとデフォルト16文字で生成
echo '16文字のランダムな文字列を生成します。'
value=`get_random_string`
echo $value
# 文字数指定あり
echo '5文字のランダムな文字列を生成します。'
value=`get_random_string 5`
echo $value
使用例です。
$ bash my_script.sh
16文字のランダムな文字列を生成します。
cL5mIswaTtRwZgpa
5文字のランダムな文字列を生成します。
V6RzE
もし使用可能な文字を変更したい場合は chars
の文字列を変更します。マルチバイト文字でも対応可能です。
引数を定義して、生成する文字数と同じように動的に指定も可能です。
コマンドを組み合わせてワンライナー
いちいち関数定義なんてやってられないとき、コマンドを組み合わせてワンライナーで書きたいときは以下のようにしたら可能です。
$ head -c 10 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | cut -c 1-10
実装内容は以下の通りです。
head
で 10バイト/dev/urandom
から読み出すbase64
でエンコード- 正規表現
a-zA-Z0-9
に一致しない文字を消す - 得られた文字列から欲しい文字数だけ取り出す
注意点として関数として定義した例と比べ、base64
のエンコード結果の文字列は a-zA-Z0-9/+
の64種から構成されるので、その中からしか使用可能な文字種を定義できません。=
もありますが末尾につくだけなので無視します。
base64 自体は偏りなく64種の文字に変換されるはずなので /dev/urandom
を使えばランダムな文字列になります。
base64
は読みだしたバイト数よりもエンコード結果の文字数が大きくなるので確率的には /
と +
を削除した結果はちゃんと必要な文字数あるはずです(たぶん?)。もし文字種を絞るなら読み出すバイト数をもっと大きくしないといけないです。というよりある程度大きいバイト数読み出しておけば安心だと思います。
$ head -c 10 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | cut -c 1-10
V82wKvCdKM
$ head -c 10 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | cut -c 1-10
9unKdKz4Ht
$ head -c 10 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | cut -c 1-10
oxOgG9jIz1
$ head -c 10 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | cut -c 1-10
bixrd0i56t
$ head -c 10 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | cut -c 1-10
LKSF2TOyAy
こんな結果になります。ちゃんと10文字生成されてランダムな結果になっています。
以上。
コメントを書く