jq 1.7の新機能ーelseなしのif

[JSON](https://datatracker.ietf.org/doc/html/rfc8259)処理のコマンドラインツールである[`jq`](https://stedolan.github.io/jq/)が1.7にアップデートして、もうそろそろ1年です（2023年9月リリース）。1.6からの改定や新機能も定着してきたと思います。

全容は[Github上のリリースノート](https://github.com/jqlang/jq/releases)を見ていただくとして、今日は誰しも1度はつまずいたことのある`else`必須の`if`です。

### これまでは

`jq`の`if`は変わっていて、条件に合致しない`else`時の処理も必ず記述しなければなりませんでした。`else`ブロックでなにもしたくないときは、明示的に`empty`と書きます。

入力が`[1, 2, 3, 4]`で、要素が偶数のときは「2 even」のように出力するが、奇数のときはなにもしないのなら、次のように書きます。

```bash
$ jq-1.6 --version                         # バージョンを確認
jq-1.6

$ echo '[1, 2, 3, 4]' | jq-1.6 '.[] | if . % 2 == 0 then tostring + " even" else empty end'
"2 even"
"4 even"
```

`else empty`を除くとエラーが発生します。

```bash
$ echo '[1, 2, 3, 4]' | jq-1.6 '.[] | if . % 2 == 0 then tostring + " even" end'
jq: error: syntax error, unexpected end (Unix shell quoting issues?) at <top-level>, line 1:
.[] | if . % 2 == 0 then tostring + " even" end
jq: error: Possibly unterminated 'if' statement at <top-level>, line 1:
.[] | if . % 2 == 0 then tostring + " even" end
jq: 2 compile errors
```

### これからは

条件が合致しないときの`else empty`は省くことができます。

ただし、省かれたときは`.`が実行されます。つまり、`else .`と解釈されるので、上記をそのまま実行すると、思ったのと違う結果になります。

```bash
$ jq --version
jq-1.7.1                                   # 1.7です

$ echo '[1, 2, 3, 4]' | jq '.[] | if . % 2 == 0 then tostring + " even" end'
1                                          # デフォルトで else 時には . 
"2 even"
3                                          # ここもそう
"4 even"
```

なので、省略したいのなら、`else`時にしたいことを実行するようにロジックを反転しなければなりません。

```bash
$ echo '[1, 2, 3, 4]' | jq '.[] | if . % 2 != 0 then empty end'
2
4
```

これだと「2 even」にはならないので、パイプ経由で`.`の処理を加えます。

```bash
$ echo '[1, 2, 3, 4]' | jq '.[] | if . % 2 != 0 then empty end | tostring + " even"'
"2 even"
"4 even"
```


### おわりに

```bash
$ echo '[1, 2, 3, 4]' | jq '.[] | if . % 2 == 0 then tostring + " even" else empty end'
$ echo '[1, 2, 3, 4]' | jq '.[] | if . % 2 != 0 then empty end | tostring + " even"'
```

どちらが見やすいかと言われるとどちらも微妙です。用例がよくなく、この新機能の真価がわかりにくいだけかもしれません。

同じことをするのなら、条件式が満たされるときのみ`.`を出力をする`select`のほうがわかりがよいでしょう。これなら、v1.6でも動作します。

```bash
$ echo '[1, 2, 3, 4]' | jq '.[] | select(. % 2 == 0) | tostring + " even"'
"2 even"
"4 even"
```

あるいはこう。

```
$ echo '[1, 2, 3, 4]' | jq 'map(select(. % 2 == 0) | tostring + " even")[]'
"2 even"
"4 even"
```

いずれにせよ、さらに多様な書き方ができるようになったので、「There's more than one way to do it」の精神的には歓迎すべきでしょう。


### 参考

- [./jq](https://stedolan.github.io/jq/) ... `jq`のオフィシャルサイトです（英文）。
- [Github jqland/jq Releases](https://github.com/jqlang/jq/releases) ... `jq`のリリースノートです（英文）。
- 『[jqハンドブック](http://www.cutt.co.jp/book/978-4-87783-491-3.html)』（2021）... `if`、`select`、代替演算子の`//`、`try-catch`など制御文関係はこの本の第10章で紹介しています。ご購入はこちらから【 [出版社](http://www.cutt.co.jp/book/978-4-87783-491-3.html) | [honto](https://honto.jp/netstore/pd-book_31037910.html) | [amazon.co.jp](https://www.amazon.co.jp/jq/dp/4877834915) | [ヨドバシカメラ](https://www.yodobashi.com/product/100000009003450000/) 】。
- 「[jqのむだづかい](https://qiita.com/stoyosawa)」 ... `jq`ではまずやろうとは思わない処理の探求記録です。完成版は他の（通常機能な）レシピとともに『[jqクックブック](https://www.cutt.co.jp/book/978-4-87783-508-8.html)』（2023）に掲載しました。ご購入はこちらから【 [出版社](https://www.cutt.co.jp/book/978-4-87783-508-8.html) | [honto](https://honto.jp/netstore/pd-book_32427461.html) | [amazon.co.jp](https://www.amazon.co.jp/dp/4877835083) | [ヨドバシカメラ](https://www.yodobashi.com/product/100000009003710680/) 】。

<img src="http://www.cutt.co.jp/book/images/978-4-87783-491-3.png" width="200" alt="表紙"></img> <img src="https://www.cutt.co.jp/book/images/978-4-87783-508-8.png" width="200" alt="表紙"></img>