今更ながら知った役立つコマンドラインツール

## 目次

- jq
- q
- yq
- xq
- tomlq

---

# `jq`

コマンドライン上で、JSON形式のデータを扱うことのできるコマンド。
APIの実行結果など、JSON形式で返ってくることが多いデータから特定の値を確認したり、データを整形して次のAPI実行等に持ちまわせる。

### インストール

WSL2のUbuntu-18.04ディストリビューションでは、

```shell
sudo apt install jq
```

でインストール可能でした。
その他は[こちら](https://stedolan.github.io/jq/download/)

### 使用例

```shell
$ cat sample.json
{
        "hoge": "fuga",
        "piyo": {
                "foo": [
                        "bar",
                        "baz"
                ]
        }
}

# `.` がルートになっている
$ jq '.' sample.json
{
  "hoge": "fuga",
  "piyo": {
    "foo": [
      "bar",
      "baz"
    ]
  }
}

$ jq '.hoge' sample.json
"fuga"

# リストは添え字で
$ jq '.piyo.foo[0]' sample.json
"bar"

# 値を更新したものを返すことも可能
$ jq '.hoge = "hogehoge"' sample.json
{
  "hoge": "hogehoge",
  "piyo": {
    "foo": [
      "bar",
      "baz"
    ]
  }
}

# `map` や `select` といった記法がある
$ cat sample2.json
[
  {
    "key": "aaa",
    "flag": true
  },
  {
    "key": "bbb",
    "flag": false
  },
  {
    "key": "ccc",
    "flag": null
  }
]

# パイプで入力を受け取ることが可能
$ cat sample2.json | jq 'map(select(.flag))'
[
  {
    "key": "aaa",
    "flag": true
  }
]

# `jq` コマンドの引数の中でパイプを使用することができる
$ cat sample2.json | jq '.[0] | .key="xxx"'
{
  "key": "xxx",
  "flag": true
}
```

---

# `q`

`jq`系列のCSV版。こちらはSQL（構文はSQLite）を介してデータを操作できます。

### インストール

公式が[インストール方法の一覧](http://harelba.github.io/q/#installation)を用意しているのですが、`apt` や `npm` でインストールする方法が載っていませんでした。ダメ元で `sudo apt install q` とやってみても「そんなものないよ！」と言われる始末。

———と思ってたら、`q` ではなく `q-text-as-data` というパッケージ名でインストールできるらしいです。

```shell
sudo apt install q-text-as-data
```

### 使用例

テストデータはこちらで作成しました。
https://tm-webtools.com/Tools/TestData

```shell
$ cat sample.csv
No,Name,Age,email
1,戸塚 大地,17,bDiQPy@test.com
2,坂上 紗彩,42,nguYYhF@test.net
3,藤村 奈穂,62,s0lvR9j@test.com
4,神野 琴美,53,cfRs8H4W@example.com
5,肥田 冨美子,11,ij2oZ@sample.co.jp
6,藤倉 美和,16,tnc72p@example.org
7,有本 栄美,31,w5CGY7P@sample.co.jp
8,友田 春男,41,CjB9kQe3@sample.com
9,崎山 正子,33,Ax9cXZhOP@sample.com
10,下山 睦,12,ubXj6@example.jp

# `-` でパイプした入力を受け付け
$ cat sample.csv | q -H -d , 'SELECT No, Name, Age FROM - WHERE Age >= 20'
2,坂上 紗彩,42
3,藤村 奈穂,62
4,神野 琴美,53
7,有本 栄美,31
8,友田 春男,41
9,崎山 正子,33

# 直接ファイル名を指定することも可能
$ q -H -d , 'SELECT No, Name, Age FROM sample.csv WHERE Age >= 20'
2,坂上 紗彩,42
3,藤村 奈穂,62
4,神野 琴美,53
7,有本 栄美,31
8,友田 春男,41
9,崎山 正子,33
```

---

# `yq`

`jq`系列のYAML版。扱い方はほとんど同じですがPython製とGo製の2種類があるので注意。

- Python製 ... 内部でJSONにパースしてからクエリを実行する。`jq`が無いと動かない。
- Go製 ... `jq`を必要とせず、Python製と比べて少し機能が多い。

単に指定したキーを取り出したり整形する程度であればどちらでも問題なさそうです。

### インストール

```
pip3 install yq
```

### 使用例

`jq` とほぼ同じように使用できます。

```shell
$ cat sample.yml
hoge: "fuga"
piyo:
  foo:
    - "bar"
    - "baz"

# `.` がルート。オプションを指定しないと出力はJSON形式
$ yq '.' sample.yml
{
  "hoge": "fuga",
  "piyo": {
    "foo": [
      "bar",
      "baz"
    ]
  }
}

# `-y` オプションでYAML形式で出力できる。YAMLファイルに書き込む場合はこちら
$ yq -y '.' sample.yml
hoge: fuga
piyo:
  foo:
    - bar
    - baz

$ yq '.hoge' sample.yml
"fuga"

# リストは添え字で
# YAMLファイルではダブルクォーテーションが無くても、出力にはダブルクォーテーションがついてくる
$ yq '.piyo.foo[0]' sample.yml
"bar"

# 値を更新したものを返すことも可能
$ yq -y '.hoge = "hogehoge"' sample.yml
hoge: hogehoge
piyo:
  foo:
    - bar
    - baz
```

---

# `xq`

`jq`系列のXML版です。`yq` と同じく `jq` のラッパーなので、使い方はほとんど同じです。おそらく `jq` が使えないとこれも使えない。

### インストール

https://github.com/maiha/xq.cr#installation
GitHubには「バイナリがあるよ」とあるのですが、

https://blog.lazy-evaluation.net/posts/linux/jq-xq-yq.html#_xml
どうやら `yq` を `pip3` でインストールすると自動でついてくるみたいです。

### 使用例

――の前に注意！

XMLの文法なのかもしれませんが、トップレベルに複数の要素を並べることはできないようです。

```shell
$ cat sample_ng.xml
<hoge>fuga</hoge>
<piyo>
  <foo>bar</foo>
  <foo>baz</foo>
</piyo>

$ xq '.' sample_ng.xml
xq: Error running jq: ExpatError: junk after document element: line 2, column 0.

$ xq '.hoge' sample_ng.xml
xq: Error running jq: ExpatError: junk after document element: line 2, column 0.
```

### ということで使用例

```shell
$ cat sample.xml
<root>
  <hoge>fuga</hoge>
  <piyo>
    <foo>bar</foo>
    <foo>baz</foo>
  </piyo>
</root>

# 一番外側の要素は付いてくる
$ xq '.' sample.xml
{
  "root": {
    "hoge": "fuga",
    "piyo": {
      "foo": [
        "bar",
        "baz"
      ]
    }
  }
}

# こうするとこれまで通りのデータが手に入る
$ xq '.root' sample.xml
{
  "root": {
    "hoge": "fuga",
    "piyo": {
      "foo": [
        "bar",
        "baz"
      ]
    }
  }
}

# `-x` オプションでXML形式で出力可能
$ xq -x '.root' sample.xml
<hoge>fuga</hoge><piyo>
  <foo>bar</foo>
  <foo>baz</foo>
</piyo>
```

---

# `yq` と `xq`

`yq` コマンドで `-x` オプションを、`xq` コマンドで `-y` オプションを付けることでデータを変換して出力できます。

```shell
$ yq -x '.' sample.yml
<hoge>fuga</hoge><piyo>
  <foo>bar</foo>
  <foo>baz</foo>
</piyo>

$ xq -y '.root' sample.xml
hoge: fuga
piyo:
  foo:
    - bar
    - baz
```

---

# `tomlq`

`yq`のGitHubを見ていたら見つけた。まだ兄弟がいたという...。

こちらはRust言語で書かれた、TOMLファイルを操作するコマンドです。

### 使用例

```shell
# せっかくなので(?)、Cargo.tomlファイルを見てみます
$ cargo new _test && cd $_
     Created binary (application) `_test` package

$ cat Cargo.toml
[package]
name = "_test"
version = "0.1.0"
authors = ["watanabe_masaki <watanabe_masaki@uniquevision.co.jp>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

$ tomlq 'package' -f Cargo.toml
name = "_test"
version = "0.1.0"
authors = ["watanabe_masaki <watanabe_masaki@uniquevision.co.jp>"]
edition = "2018"

$ tomlq 'package.version' -f Cargo.toml
0.1.0

# 配列は添え字アクセスはできなそう？
$ tomlq 'package.authors[0]' -f Cargo.toml
package.authors[0] not found!
```

---

# おわりに

Linux環境を使い始めたのも入社してからで、コマンドライン芸はまだまだ不慣れですが、探してみると面白いものがいっぱいあるよう興味が出てきました。
JSON等を扱うならそれを扱う小さなプログラムを書いて...、とやっていた手間を無くせそうなので、候補として名前を覚えておくだけでもすごく意味がありそうです。
これを機に毛嫌いせずコマンドラインツールを色々扱えるようになっていきたいです。