読者です 読者をやめる 読者になる 読者になる

walkingmask’s development log

IT系の情報などを適当に書いていきます

MENU

How to create a self made command (on Mac) シェルコマンド作成

自分でシェルコマンド作ってみたい欲が高まり過ぎたので,作成しちゃったのをlog.

環境

OS X version 10.11.2
Apple LLVM version 7.0.2 (clang-700.1.81)

rands

作成したコマンドは rands というもので,ランダムな文字列を出力するというもの.最近,講義でランダムな文字列を扱う機会が多かったのでいっそ作ったるということで作成.楽しかった.
github.com
デフォルトだと,アルファベット・記号・数字がごっちゃになった8文字を出力.オプション与えると,文字列長設定したり記号除外したりスペースを含められたりという感じのもの.
f:id:walkingmask:20160116231049p:plain

ソースコード

ちょっとソースコードに関して解説.

getopt関数

getopt関数はシェルコマンドで引数を処理してる標準関数.ハイフン後に続く文字を解釈して,いろいろ返してくれる.ググったら色々ドキュメントが出てくる.
Man page of GETOPT
コマンドライン引数の取得とgetopt
getoptによるオプション解析
がしかし...最初は

$ rands 10 -an
$ rands -A 10

みたいな感じで,文字列長はハイフンなしで適当に指定したかったのだが,ハイフンなしの引数の処理がイマイチわからなかったので,そこは今後の課題に.特に,ハイフン無し引数がハイフンより先に来た時は,他の引数も処理してくれなかったのが謎だった.

rand()とtimeval.tv_usec

最初は

srand((unsigned) time(NULL));
rand();

だけで実装しようとしたのだが,連続実行すると文字列に変化がないので,マイクロ秒まで使ってsrandを指定するようにした.
8ttyan.hatenablog.com

struct timeval tv;
gettimeofday(&tv, NULL);
srand((unsigned) tv.tv_usec);

がしかし...これでも複数回実行すると,文字列に規則性があるのが見えてくる.実装で,ランダム値によって文字と記号と数字のどれを出力するかを決めてるのが問題になってるっぽい.

switch((random()%5+1){
    case 1:
...
}

ここも,よりランダムっぽくなるように,timeval.tv_usecを使って以下のように工夫した

switch((random()+myTime.tv_usec)%5+1){
    case 1:
...
}

これで,かなりランダムに出力されるようになった気がした.

コマンド化

qiita.com
Cのソースコードをそのままコンパイルしただけでは,実行する際に

$ ./rands -l 10 -nA

みたいに実行ファイルの場所を指定しなくてはいけないので,他のシェルコマンドのように実行できるようにする.それが install.sh に描かれている.やっていることは,

これだけで,自分で作成したプログラムをシェルコマンドみたいに使うことができる!

まとめ

getoptやrandのいい練習にもなって,自作コマンドを作れて楽しかった!まだまだ学ぶことは多いけど,今後もガンガン自作コマンド作っていきたい.あとは,シェルスクリプトもコマンド化できるみたいなので,その辺もガンガン作っていきたい.

追記1

例えば,.zshrcなどに

export PATH=$PATH:/Users/$USER/bin

のように追記して,/Users/$USER/bin をそのまま bin として利用すれば,お手軽自作コマンドが捗る!
qiita.com
こんな感じで,シェルスクリプトもコマンド化できるみたい.