ioknifeというパッケージを作りはじめた
はじめに
ioknifeというパッケージを作りはじめた。日常生活におけるちょっとしただるさを改善するようなコマンドを用意したいという思いで。
基本的にはioknifeというコマンドの中に色々欲しくなったらサブコマンドを追加していくというような方針(いまはrest,grepo,tooの3つだけ)。
言語は?
最初はpythonで作るかgoで作るかrustで作るか迷ったのだけれど、結局pythonで作ることにした。 速さはあまり要らないような細々とした処理を想定しているということと、まだどのような処理を追加したいかがあやふやなので動的に色々渡せるような何かがありえるかもしれないかなーと思ったりしているので。
いつか便利なサブコマンドができて、そしてそのサブコマンドの速度が気になったときに、それだけをrustなりで作るのが良さそうかなとおもったりした。
ちょっとした裏テーマとして、標準ライブラリのみで書く、mypyである程度まじめに型チェックをしてみる、というようなことを考えてたりはしている(標準ライブラリは概ねtypeshedにあるので)。
install方法
はい。
$ pip install ioknife
今の所存在するサブコマンドたち
今の所存在するサブコマンドは以下の3つ。
- rest
- grepo
- too
help messageは概ねいつものどおり。
$ ioknife -h usage: ioknife [-h] [--logging {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET}] [--debug DEBUG] {rest,grepo,too} ... positional arguments: {rest,grepo,too} optional arguments: -h, --help show this help message and exit --logging {CRITICAL,FATAL,ERROR,WARN,WARNING,INFO,DEBUG,NOTSET} --debug DEBUG
ioknife rest
restコマンドは関数のhead,tailのtailをイメージするとわかりやすいかもしれない。行をリストの要素になぞらえた形の。ただし、取り除かれるであろう先頭のN行は表示しないのではなくstderrの出力される。
どういう時に使うかと言うと、先頭にヘッダーが付加されるようなコマンドをgrepするような時に。典型的な例はpsコマンド。
通常のpsコマンドでgrepした場合にはヘッダー行が喪われてしまう。以下の様に。
$ ps aux | grep -i bash podhmo 4435 0.0 0.0 10052 6336 pts/1 Ss+ 6月09 0:06 /bin/bash podhmo 4440 0.0 0.0 10328 6544 pts/2 Ss+ 6月09 0:09 /bin/bash podhmo 6431 0.0 0.0 9144 5288 pts/0 Ss 6月20 0:00 bash podhmo 7832 0.0 0.0 9128 4932 pts/6 Ss 6月19 0:00 /bin/bash --noediting -i podhmo 9100 0.0 0.0 7308 2300 pts/6 S+ 00:49 0:00 grep --color=auto -i bash podhmo 28622 0.0 0.0 9276 5408 pts/3 Ss+ 6月19 0:00 /bin/bash podhmo 28641 0.0 0.0 9408 5412 pts/4 Ss+ 6月19 0:00 /bin/bash
本来は以下のようなヘッダー行が表示されるのだけれど隠れてしまう。
$ ps aux | head -n 1 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
これをstderrに表示してあげると便利というようなコマンド(-n 1
はデフォルトなので省略しても大丈夫)。
そしてstderrはgrepの対象にはならないのでconsole上には表示される。便利。
$ ps aux | ioknife rest -n 1 | grep bash USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND podhmo 4435 0.0 0.0 10052 6336 pts/1 Ss+ 6月09 0:06 /bin/bash podhmo 4440 0.0 0.0 10328 6544 pts/2 Ss+ 6月09 0:09 /bin/bash podhmo 6431 0.0 0.0 9144 5288 pts/0 Ss 6月20 0:00 bash podhmo 7832 0.0 0.0 9128 4932 pts/6 Ss 6月19 0:00 /bin/bash --noediting -i podhmo 9185 0.0 0.0 7176 2424 pts/6 S+ 00:51 0:00 grep --color=auto bash podhmo 28622 0.0 0.0 9276 5408 pts/3 Ss+ 6月19 0:00 /bin/bash podhmo 28641 0.0 0.0 9408 5412 pts/4 Ss+ 6月19 0:00 /bin/bash
ioknife grepo
grepoコマンドは grep -o <pattern>
を模したコマンド。grepの -o
オプションはマッチした部分のみを抽出するオプションでほかのコマンドにパイプで渡すような時に結構重宝する機能。
一方で、その行自体の内容がわからなくなる。これも同様にstderrに出力されれば便利なのでは?というような形で作成したもの。
例えば、先程のpsの例をgrepで取り出してみる。
$ ps aux | grep -o -P "[^ ]+/bash" /bin/bash /bin/bash /bin/bash /bin/bash /bin/bash
何がなんだかわからない。これをgrepoを使うと以下の様な表示になる。実は分かりづらいけれどstderrの表示は灰色っぽい感じの色で表示される。
$ ps aux | ioknife grepo "[^ ]+/bash" matched: podhmo 4435 0.0 0.0 10052 6336 pts/1 Ss+ 6月09 0:06 /bin/bash /bin/bash matched: podhmo 4440 0.0 0.0 10328 6544 pts/2 Ss+ 6月09 0:09 /bin/bash /bin/bash matched: podhmo 7832 0.0 0.0 9128 4932 pts/6 Ss 6月19 0:00 /bin/bash --noediting -i /bin/bash matched: podhmo 28622 0.0 0.0 9276 5408 pts/3 Ss+ 6月19 0:00 /bin/bash /bin/bash matched: podhmo 28641 0.0 0.0 9408 5412 pts/4 Ss+ 6月19 0:00 /bin/bash /bin/bash
ちなみにpythonでナイーブに実装されているのでそんなに早くない。そこそこ大きめのファイルなどに対して使いたい場合には、以下のようにgrepなどの後に使った方が良い(二重にパターンを書かなければいけないのがめんどくさかったりはする)。
$ ps aux | grep -P "[^ ]+/bash" | ioknife grepo "[^ ]+/bash"
実行例は以下の様な感じ。
ioknife too
tooコマンドはtoo.jsにとても影響を受けている。
説明自体もtoo.jsの以下のものそのまま。
Combine multiple commands' stream, keep all foreground and kill all in one Ctrl+C
自作した理由は、日常的な環境ではnpmに依存したものをあまり使いたくなかったなーということとasyncioとsubprocessを使って遊んでみたかったので(CI経由でそう言えばcontextlib.asynccontextmanager()とasyncio.run()がpython3.7からだったということを思い出したりしていた)。
実行した例は以下の様な感じ。雰囲気で色が付く。
--shell
オプションを有効にするとシェルを経由して実行される(experimental)。--dump-context
を付けるとどんな感じの雰囲気で実行されるか分かる。
$ ioknife too --dump-context --shell --cmd 'for i in $(seq 3); do echo "--" $i; sleep 0.4; done' --cmd 'for i in $(seq 3); do echo "\*\*" $i; sleep 0.4; done' ['for', 'i', 'in', '$(seq', '3);', 'do', 'echo', '--', '$i;', 'sleep', '0.4;', 'done'] ['for', 'i', 'in', '$(seq', '3);', 'do', 'echo', '\\*\\*', '$i;', 'sleep', '0.4;', 'done'] $ ioknife too --shell --cmd 'for i in $(seq 3); do echo "--" $i; sleep 0.4; done' --cmd 'for i in $(seq 3); do echo "\*\*" $i; sleep 0.4; done' [0] for -- 1 [1] for ** 1 [0] for -- 2 [1] for ** 2 [0] for -- 3 [1] for ** 3
ちなみに --cmd
と入力するのが面倒だったのでstdinからも受け取れるようにした。ただし渡せるファイルのフォーマットは後で変更するかもしれない。
/tmp/x
for i in $(seq 10); do echo "--" $i; sleep 0.1; done for i in $(seq 10); do echo "@@" $i; sleep 0.1; done
使った結果。
$ cat /tmp/x | ioknife too --shell --dump-context ['for', 'i', 'in', '$(seq', '10);', 'do', 'echo', '--', '$i;', 'sleep', '0.1;', 'done'] ['for', 'i', 'in', '$(seq', '10);', 'do', 'echo', '@@', '$i;', 'sleep', '0.1;', 'done']
途中で止める。
$ cat /tmp/x | ioknife too --shell $ cat /tmp/x | ioknife too --shell [0] for -- 1 [1] for @@ 1 [0] for -- 2 [1] for @@ 2 [0] for -- 3 [1] for @@ 3 [0] for -- 4 [1] for @@ 4 [0] for -- 5 [1] for @@ 5 C-c C-cINFO:ioknife.too:send signal (Signals.SIGINT)