小さいコマンドを作る用途のシェルスクリプトとその代替
小さいコマンドを作るシェルスクリプトの良さ
シェルスクリプトは汎用言語よりもだいぶ簡潔に書ける。 例えばmainとか要らないし、コマンドの実行でカッコとかも要らない。
コマンドラインでいろいろ試したらそれをコピペ出来るのも、小さいものを作る開発生産性を高めている。 これもPython等のまともな言語を使う事に比べて、小さい作業をするのに優れている所に思う。
また、コマンドとして独立させるコストが少ない。 引数は$1, $2とかで勝手にアクセス出来るし、入出力をまとめてリダイレクト出来たり、むしろ別々のコマンドにしたくなるように設計されている。
for文とかが書きにくいのも、個々の処理を別のファイルにしてパイプでつなげてxargしたくなるという形で、 より小さいコマンドに分割したくなる圧力がある。結果も宣言的になるので、手でfor文回すより良い。
小さいコマンドをたくさん作る意義とデメリット
小さいコマンドは単純で、バグりにくく、インターフェースも単純になりやすい。
また、小さいコマンドはそれを組み合わせたよりお大きなシステムを作る時に、 そのより大きなシステムに問題が出るようなイレギュラーが発生した時に、 手作業で応急処置する時に使いやすい。 手作業に関してオープンなシステムとでも言おうか。
開発の過程で手作業で順番に作業したのを自動化していくので、手作業のプロセスが自動的に確立する所も良い。
一方でシェルスクリプトは。不要にファイルを分けたくなるくらいに分ける圧力が強すぎる事がある。 簡単な処理でも小さいコマンドを3つに分けて、しかもそれがネストされるような呼び出し構造で一番下以外独立して使えないようなケースでは、 読むのも面倒だし嬉しさもそれほどは無い。
シェルスクリプトは小さいコマンドを作る圧力があってそれが素晴らしいのだが、 その圧力が強すぎる部分もある気はする。
同じ特徴を持ったもっとモダンな代替は無いものか?
シェルの作業の楽しさや効率性、保守の容易さはそのままに、 言語的なレガシーさとかはなくした現代的な代替は無いだろうか?
普段の作業はデフォルトのシェルから変えたくない。 というのは、VSCodeのターミナルだとかSourceTreeのターミナルとかがmingwとかだったりとかで、 bashとかzshでの作業の機会はどうしても無くせないので、普段から慣れさせておかないとストレスと思うから。
でもスクリプトは別にzshとかbashである必要も無い。
ただ、replではダメだ。ちゃんとシェルとしてコマンドラインで試しつつ、それがコピペ出来るのがいい。 出来たら単一の行はbashやzshと似ていて多くのコマンドはコピペ出来るのが良いと思う。
一方でrawstringとかstring interpolationのようなのは欲しい。 汎用言語では無くてシェル特化の方が良いとは思うのだが、言語仕様はもっとモダンにならんかなぁ。
そんな風に思ってfishを見てみると、どうもスクリプト言語としては好みじゃない。
うーん、インタラクティブなシェルじゃなくて、スクリプトを置き換えたいんだよなぁ。 と思っていたら、そういえばOilってのがあったな、と思い出す。
コンセプトがまさに自分が思っているような事が書いてあるし、言語仕様も自分の好みに見える。
スクリプト用にOilってどうなんだろう?
という事で最近趣味でシェルスクリプトを書く機会がまぁまぁ多い身としては、Oilとか触ってみてもいいんじゃないか、という気もする。 今から新しい言語覚えるのかったるいなぁ、という思いもあるが。
最近いろいろ作業しているサブWikiのgit-wikiへの公開のスクリプトをoilに書き換えてみようかしら?
試しに_config.yml
を生成していたスクリプトを置き換えてみた
_config.ymlのscopeの所をサブWIkiごとに生成する部分を置き換えてみた。
Try oil for gen_configyml.sh · karino2/SubWiki@c1a6520
やっている事
やっている事は、
- 固定内容となるファイルの前半部分を出力
- ls wiki_srcの結果の各ディレクトリ名に対して、scopeとvaluesのymlを生成
- 固定内容となるファイルの後半部分を出力
という事で、これまでは1と2は別ファイルにしてあって、さらに2もxargsの先を別スクリプトファイルにしていたが、少し大げさだなぁ、と思っていた。
oilで書くと以下のようになる。
proc gen_one(file) {
echo """
-
scope:
path: "wiki/$file"
values:
permalink: /$file/:basename"""
}
for file in @(ls ../wiki_src) {
gen_one $file >> $DEST
}
雑感
最初慣れない時は普通の汎用言語使ってるのと変わらんなぁ、と思っていたが、procをインタラクティブなシェルで試すようになってからはまぁまぁシェルっぽいな、と思えるようになった。
ネストが複雑になるといまいちだなぁ、とは思うが、そうならないように書けば良いだけとも思う。 普通のシェルスクリプトのように書いて、けれどちょっとだけ1ファイルを複雑にしたい、という時にはちょうど良い気がした。
テンプレート的なのを別ファイルにしなくて良いのは楽で良いかなぁ、と思ったが、rawstringはソースを見づらくするね。 こういう事がやりたいなぁ、と思ったのが今回のエントリのきっかけだったが、やってみるといまいちだった、という<ありがち
追記: 結局別ファイルに分けるように戻した> Use outer file for long string. · karino2/SubWiki@1ebf608
言語仕様はアットマークとドルの違いがたまにハマるが、 だいたい現代的にはこんな感じにして欲しいな、という仕様になっているので、調べないでもだいたい期待通りに動く。 例えばダブルクオート3つのrawstringは中にドルで変数が書ける、とか。
procの仕様は素直でいいね。この辺はpowershellとか良く参考にしているな、と思う。 lsした結果にfor文回す、とかが簡単に書けて、そうそう、これこれ、って気分になる。
インタラクティブなシェルがだいたいbashとかと互換になるのはいいね。 ちょっとインタラクティブで試しつつ作業したい時にもreplより断然快適。
また、シェルスクリプト的なシステムの長所として、順番に置き換えていけるのもいいね。 全部をoilにする必要はなくて、普段はbashのシェルスクリプトにしておいて、 ちょっとそれだと面倒なファイルだけoilにすれば良い。 bashと似ているおかげでこういう混ぜて使うのに向いている気がする。
Syntax highlightは欲しい気はするな。書いてもいいかもしれない。