mkpasswdがどこにでもあると思うなよ!
RADIUSのshared secretやら()、初期パスワードやら、ランダムな文字列が欲しいことがまれによくあります。キーボードからグチャグチャっとやると一様性に乏しいので、ここはきちんと機械的に作りたいものです。
そんなもの、コマンド一発でありそうなものですが……?
とあるサイト「mkpasswdコマンドを引数なしで実行すると、9文字のパスワードが生成される」
いや、それ古いコマンドだし、同名で用途の違うものがあるから!
ウェブをあさってみると、こんな感じ↓のワンライナーがあちこちで紹介されています。
$ cat /dev/urandom | tr -dc "[:alnum:]" | fold -w 12 | head -n 1
この例では、英数字の12文字からなるランダム文字列をひとつ作成しています。
何をやっているかというと、乱数ソースから英数字だけの長~~~い文字列を生成して、12文字ごとに折って(改行を入れて)、一行だけ出力して終了。
これは使える!(゚∀゚) ……と、早速LinuxからSolarisに移って実行してみると……
$ cat /dev/urandom | tr -dc "[:alnum:]" | fold -w 12 | head -n 1
tr: Input file error: Illegal byte sequence
がっくし_('、3」∠)_ わけがわからないよ。
Solarisのtrでも動くランダム文字列生成
調べてみると、SolarisやmacOSでも同様の症状らしい。
原因は、範囲外の文字コードがtrに入力されたため。余計なことしやがって……
ロケールを変更すると、きちんと動くようになります。ついでに整理して短くしましょう。
$ LC_ALL=C tr -dc "[:alnum:]" </dev/urandom | fold -w 12 | head -1
4MCbSob7U0AD
うまくできました。Linuxでもこのままで使えます。
16進数のランダム値を作成してみる
とあるスクリプトで16進数のランダム値が必要になったので、改造してみます。
$ LC_ALL=C tr -dc "[:xdigit:]" </dev/urandom | fold -w 16 | head -1
7a82ECca7C9D0b87
チガウソウジャナイ...
$ LC_ALL=C tr -dc "[0-9][A-F]" </dev/urandom | fold -w 16 | head -1
D36485138D802806
うまくいったもよう。
ではLinuxの方で……、
$ LC_ALL=C tr -dc "[0-9][A-F]" </dev/urandom | fold -w 16 | head -1
[ED51]]C12FFEEC9
おうふ_('、3」∠)_
Linuxでは、こうすることで、期待した文字列が得られました。
$ LC_ALL=C tr -dc "0-9A-F" </dev/urandom | fold -w 16 | head -1
9085421AB6710C4E
ところが、これをSolarisで実行すると、
$ LC_ALL=C tr -dc "0-9A-F" </dev/urandom | fold -w 16 | head -1
0-FAA9F9FF-9-9--
と、にゃーんなことに。
調べてみると、System VとGNUでtrの仕様が大きく異なっていて、System Vでは範囲を [0-9] のように書くのに、GNU trではダメで、0-9 と書かないといけないとのこと。逆も真。なんてこったい。
LinuxとSolarisの両方で動くように書くと、こんな感じでしょうか。
$ LC_ALL=C tr -dc "[:digit:]ABCDEF" </dev/urandom | fold -w 16 | head -1
もっと良い手があるのかもしれませんが、とりあえず。
PS
つくづく、自分は地雷を踏むのがトクイです💥
ポータビリティのあるコードを書こうとすると、自然とこうなりますよ。
おわり