はじめに
皆さん、シェルは何を使っていますか?
bash?、zsh?、fish?
シェルにはそれぞれ違いがあって、皆さん独自にカスタマイズして使っていると思いますが、「自作シェル」という方はあまりいないのではないでしょうか?
今回、自作シェルに挑戦してみたので、ブログとして残しておこうと思います。
やれ「zshが一番」だとか、「fishの補完は最強」などと言っている日本人のなんと多いことか…
— sublimer (@lz650sss) April 24, 2019
というわけで、シェル自作しました。
名前は「clash」です。https://t.co/sA9W4qLMno
なんで作ったのか
Twitterの一部界隈で、「どのシェルが良いのか」で話題になっていたので、「自作シェル」という選択肢を加えたら面白そうだと思い、自作できないか調べてみました。
調べたところ、「lsh」というシェルを見つけました。(局所性鋭敏型ハッシュじゃないよ!)
github.com
lshは300行くらいのCのコードで書かれていたので、「これくらいならできそう!」と思い、これをベースに作り始めました。
命名
コードを書く前に名前を決めました。
名前は「clash」です。
clashの意味を調べてみると、
ジャンジャンと鳴る、ガチャガチャ音がする、ガチャンと音を立ててぶつかる、ぶつかる、衝突する、(競技などで)(…と)ぶつかり合う、ぶつかり合う、(…と)衝突する、(…と)かち合う、(…と)釣り合わない
とあります。
既存のシェルとぶつかり合うくらいのシェルになると嬉しいですね。
実装
コードはこちらです。
github.com
2019/4/27時点で、以下のコマンドをビルトインコマンドとして実装しています。
- echo
- cd
- pwd
- mkdir
- touch
- ls
- exit
「CUI超初心者向けシェル」といったところでしょうか。
タブ補完もコマンド履歴もない、言ってしまえばとても不便なシェルです。
bashやzshがいかに高機能か分かりますね!
仕組みですが、
clash_loop()
でループを回すclash_read_line()
で入力を受け取る- 入力された文字列を
clash_split_line()
でパースする clash_execute()
でコマンド実行
という流れになっています。
lshとの違いとして、以下の変更を加えました。
今回シェルを自作してみて、「なるほど」と思ったのは、cdコマンドの実装です。
int clash_cd(char **args) { if (args[1] == NULL) { fprintf(stderr, "clash: argument error"); } else { if (chdir(args[1]) != 0) { perror("clash"); } } return 1; }
流れとしては、
と言った感じになると理解しました。
詳しい方からすると当たり前のことかもしれませんが、シェルの仕組み自体、全く知らなかった私にとっては、シェルの仕組みを理解する良いきっかけになりました。
おわりに
まだまだ機能は足りませんが、ある程度動くものが出来たので嬉しいです。
もし良かったら、新しいコマンドを実装してプルリクを投げていただけると喜びます。