たいちょーの雑記

ぼくが3日に一度くらい雑記をかくところ

BashとかからLINQ使いたくてShelLINQってコマンド作った

BashとかからLINQ使いたくてShelLINQってコマンド作った

ウヒャァ使いやすい

LINQすき

コマンドラインでの作業をしているとき、シェルスクリプトを書いているときに突然LINQが使いたくなる人に向けて作ったコマンドです
docs.microsoft.com

似たような機能を持つ既存のものとしてはawkdatamashがあります
https://ja.wikipedia.org/wiki/AWKja.wikipedia.org
https://www.gnu.org/software/datamash/www.gnu.org

正直awkで十分にできますがぼくはLINQのが使いたかったのです

ShelLINQ

logo

github.com

インストールのしかた

git cloneしてやるだけです

git clone https://github.com/xztaityozx/shellinq
./shellinq/install.sh

aliasを貼ったり補完スクリプトbashrcに書き込むスクリプトを同梱してるので実行すれば使えるようになります

つかいかた

GitHubのREADME.mdと同じことを書くのでそっち見てもらってもいいです

shellinq [TYPEs] [method query] ... [-o [FORMAT]]

[TYPEs]は入力データの型です。int型の場合は[int]と指定します。指定しない場合はint,double,stringのどれかからShelLINQが予想します。
ls -lコマンドのように複数のカラムがある場合は[type1,type2,...,typeN]というように順番に指定します。これも指定しない場合はShelLINQがすべて予想します。

[method query]はクエリ部分です。methodにはSelectWhereのようにLINQが提供するメソッド名を指定します。Qにはメソッドに与える引数部分を指定します。
例えば

Where (x => x% 2 == 0)

where 'x => x% 2 == 0'

と書きます。
queryではawkのようにカラムの指定に$が使えます。
例えばwhere '$1%2==0'と書けばShelLINQはwhere '_=>_%2==0'と解釈します。
$0を使うとすべてのカラムが指定できます。

[-o [FORMAT]]は出力フォーマットをC#のコードで指定するときに使います。 具体的には処理されたデータを使ったforeachループのブロック部を指定します。
取り出されたアイテムは変数itemに格納されているのでそれを使用するといいでしょう。

Input

% seq 30|shellinq select '$1%2==0' -o 'Console.WriteLine(item?"even":"odd");'

output

odd
even
odd
even
.
.
.

デモ

3の倍数を抽出

seq 30 | shellinq where '$1%3==0'

demo1

3の倍数を抽出して30加算

seq 30 | shellinq where '$1%3==0' select '$1+30'

demo2

ls -lの出力を複数カラム纏めて出力

ls -l | sed '1d' | shellinq select 'new Tuple<string,int>($1,$5)'

demo3

これから

複数カラムを選択する場合が今のところかなり面倒なので何とかしたいと思っています

ls -l | sed '1d' | shellinq select '$1,$5'

ぐらいで書けると楽にできそうです

あとは入力をファイル指定出来るようにもしたいですね

雑記

ここからは雑記です
もともと雑記ですけど・・・

実装

ShelLINQは受け取ったクエリと標準入力を元に C#のソースコードを吐き出してmcsでビルド しています
なので処理の実態部分はC#です
それゆえにawk比べると速度はあまり出ません

ソースコードの生成には主に置換を使っています
例えば$1は内部クラスのメンバ変数Item1に置換されます
クエリ内に$1が表れるとItem1に置換されメソッドチェーンに連結されます
なので複雑なコードには対処できないと思います・・・(スイマセン)

C#であるためデータのに注意する必要があります
デモ3のようにstringintと書いてやらないとエラーで死にます
この辺は今後の改良で対処したいと思っています

出力について

上記まででわかる通り置換によってソースコードを作っているため期待通りの出力が得られないことがあると思います

例えばGroupByメソッドを使う場合です
img1

期待しているのと違う出力のほうが出がちです
Selectなどでうまく書いてやる必要がありますがここはLINQの知識が必要なので頑張らないとダメです
この辺の解決のために-oオプションを付けていますがstring.Joinなどで結合するようにすることを予定しています

まとめ

正直LINQが書けて超楽しいです
やることはawkで済む場合のことが多いですけど
良かったらみんなさんも使ってみてください

それではいいShelLINQライフを!