hgot07 Hotspot Blog

主に無線LANや認証連携などの技術についてまとめるブログです。ネコは見る専。

SolarisでもLinuxでも動くランダム文字列生成

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でも動くランダム文字列生成

調べてみると、SolarismacOSでも同様の症状らしい。

原因は、範囲外の文字コードが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 と書かないといけないとのこと。逆も真。なんてこったい。

 

LinuxSolarisの両方で動くように書くと、こんな感じでしょうか。

  $  LC_ALL=C tr -dc "[:digit:]ABCDEF" </dev/urandom | fold -w 16 | head -1

 

もっと良い手があるのかもしれませんが、とりあえず。

 

PS
つくづく、自分は地雷を踏むのがトクイです💥
ポータビリティのあるコードを書こうとすると、自然とこうなりますよ。

 

おわり