Twitter で見かけた jc コマンドが便利そうなので少し使ってみたメモ。
jc コマンドのバージョン。
$ jc -a | jq -r .version 1.13.4
jc コマンドの使い方
jc コマンドとは
jc JSONifies the output of many CLI tools and file-types for easier parsing in scripts.
jc コマンドはいろいろな CLI ツールとかファイルタイプの出力を JSON 化するので jc コマンドの出力をパイプで jq コマンドに渡して簡単にフィルタリングしたり加工することができる。 なんとなくだけど Windows の PowerShell に近いイメージ。PowerShell はコマンドの出力そのものがオブジェクトだから JSON とはぜんぜん違うけど、フラットなテキストを JSON に構造化するだけでもかなり強力。
jc コマンドの使い方をいくつか書いてみる。
特定のファイルサイズ以上のファイルだけを出力する。
$ ls -l /usr/bin | jc --ls | jq '.[] | select(.size > 50000000)'
{
"filename": "docker",
"flags": "-rwxr-xr-x",
"links": 1,
"owner": "root",
"group": "root",
"size": 68677120,
"date": "Aug 14 19:41"
}
$ cat << EOF | jc --csv -p
name,age
Tanaka,20
Takahashi,40
EOF
[
{
"name": "Tanaka",
"age": "20"
},
{
"name": "Takahashi",
"age": "40"
}
]
$ ping www.google.com -c 2 | jc --ping -p
{
"destination_ip": "216.58.197.228",
"data_bytes": 56,
"pattern": null,
"destination": "www.google.com",
"packets_transmitted": 2,
"packets_received": 2,
"packet_loss_percent": 0.0,
"duplicates": 0,
"round_trip_ms_min": 33.183,
"round_trip_ms_avg": 38.236,
"round_trip_ms_max": 43.29,
"round_trip_ms_stddev": 5.053,
"responses": [
{
"type": "reply",
"bytes": 64,
"response_ip": "216.58.197.228",
"icmp_seq": 0,
"ttl": 114,
"time_ms": 33.183,
"duplicate": false
},
{
"type": "reply",
"bytes": 64,
"response_ip": "216.58.197.228",
"icmp_seq": 1,
"ttl": 114,
"time_ms": 43.29,
"duplicate": false
}
]
}
インストール方法
jc コマンドの README の Installation を見ると apt-get とか pacman とかいろいろなパッケージマネージャーに対応しているっぽい。
自分は Mac を使っているので Homebrew でインストールした。
$ brew install jc
使い方
jc コマンドは標準入力のパイプから受け取った入力を JSON にして標準出力に出力するのでこんな感じに使っていく。
$ COMMAND | jc PARSER [OPTIONS]
jc コマンドは "magic" 構文というのが使えるのだけど、↑のコマンドは "magic" 構文ではこんな感じに使っていく。
$ jc [OPTIONS] COMMAND
通常の構文でも "magic" 構文でも手に馴染むほうを使うでよさそうだけど "magic" 構文はコマンドのエイリアスをサポートしていないのと "magic" 構文は jc コマンドのオプションはコマンドの前に指定する必要があるのは気をつけていく。
"magic" 構文はコマンドのエイリアスをサポートしていないので ll='ls -l' みたいなエイリアスがあるときに ll | jc --ls はちゃんと動くけど jc ll はエラーになる。
あと "magic" 構文は jc コマンドのオプションはコマンドの前に指定する必要があるので jc -p ls はちゃんと動くけど、jc ls -p は -p が ls コマンドのオプションとして解釈してしまって意図通りには動かない。
-p オプション: JSON の出力をフォーマットする
-p オプションを指定すると JSON の出力をフォーマットする。
$ ls
a.txt b.txt
$ ls | jc --ls
[{"filename": "a.txt"}, {"filename": "b.txt"}]
$ ls | jc --ls -p
[
{
"filename": "a.txt"
},
{
"filename": "b.txt"
}
]
-m オプション: JSON をモノクロ出力する
-m オプションを指定すると JSON をモノクロで出力する。
jc コマンドはデフォルトは JSON をカラー化して出力するけど -p オプションを指定すると JSON をカラー化せずに出力する。
-r オプション: JSON を raw 出力
-r オプションを指定すると JSON のすべての値を文字列として出力する。
↓ -r オプションを指定しないとき。
$ ls -l | jc --ls -p
[
{
"filename": "a.txt",
"flags": "-rw-r--r--",
"links": 1,
"owner": "ebi",
"group": "staff",
"size": 0,
"date": "9 25 23:30"
},
{
"filename": "b.txt",
"flags": "-rw-r--r--",
"links": 1,
"owner": "ebi",
"group": "staff",
"size": 0,
"date": "9 25 23:30"
}
]
↓ -r オプションを指定するとき。
$ ls -l | jc --ls -p -r
[
{
"filename": "a.txt",
"flags": "-rw-r--r--",
"links": "1",
"owner": "ebi",
"group": "staff",
"size": "0",
"date": "9 25 23:30"
},
{
"filename": "b.txt",
"flags": "-rw-r--r--",
"links": "1",
"owner": "ebi",
"group": "staff",
"size": "0",
"date": "9 25 23:30"
}
]
-a オプション: jc コマンドの使い方を出力する
-a オプションを指定すると jc コマンドの使い方とか利用できるパーサーとか author とかバージョンを出力する (出力はもちろん JSON)
$ jc -ap | head -n 25
{
"name": "jc",
"version": "1.13.4",
"description": "JSON CLI output utility",
"author": "Kelly Brazil",
"author_email": "kellyjonbrazil@gmail.com",
"parser_count": 57,
"parsers": [
{
"name": "airport",
"argument": "--airport",
"version": "1.1",
"description": "airport -I command parser",
"author": "Kelly Brazil",
"author_email": "kellyjonbrazil@gmail.com",
"compatible": [
"darwin"
],
"magic_commands": [
"airport -I"
]
},
{
"name": "airport_s",
"argument": "--airport-s",
互換性
jc コマンドのパーサーはたくさんあって ls, ps, dig みたいなパーサーはどんなプラットフォームのコマンドの出力もパースできるけど、コマンドの出力がプラットフォームによって変わってくるとちゃんとパースできないよう。
このへんは jc -a の出力を jq でフィルタすると対象のプラットフォームで利用可能なパーサーが確認できる。
たとえば Windows で利用可能なパーサーはこんな感じで確認していく。
$ jc -a | jq -r '.parsers[] | select(.compatible | contains(["win32"])) | .name' csv env hosts ini kv pip_list pip_show xml yaml
プラットフォームは Linux が一番多くのパーサーに対応しているっぽい。
$ jc -a | jq -r '.parsers[] | select(.compatible | contains(["linux"])) | .name' | wc -l
55
$ jc -a | jq -r '.parsers[] | select(.compatible | contains(["darwin"])) | .name' | wc -l
39
$ jc -a | jq -r '.parsers[] | select(.compatible | contains(["win32"])) | .name' | wc -l
9
$ jc -a | jq -r '.parsers[] | select(.compatible | contains(["cygwin"])) | .name' | wc -l
16