TL; DR
- jd を使えば、2つのJSONの差分をフィールド単位で取得できる!
$ cat a.json
{"foo": {"bar": 1, "baz": 2}}
$ cat b.json
{"foo": {"bar": 1, "baz": 3}}
$ jd a.json b.json
@ ["foo","baz"]
- 2
+ 3
はじめに
更新処理前後の差分等、2つの以上のJSONファイルを見比べる際に、diff
コマンドを使うことがあると思います。
しかし、diff
コマンドは差分が行単位でしか出ないため、 jq
で整形してもフィールド名しか出てこず「結局差分はどこで起きているんだ?」と探し回る必要があります。
$ diff <(cat a.json | jq) <(cat b.json | jq)
4c4
< "baz": 2
---
> "baz": 3
そこで今回は、JSONの構造に基づいて差分を出してくれる jd
コマンドを紹介したいと思います。
バージョン
$ jd -version
jd version 1.6.1
使い方
引数の渡し方は diff
と同じです。差分をフィールドのフルパスで出してくれるので、変更箇所が一目瞭然です。
$ cat a.json
{"foo": {"bar": 1, "baz": 2}}
$ cat b.json
{"foo": {"bar": 1, "baz": 3}}
# 差分表示、@行がフィールドのフルパス
$ jd a.json b.json
@ ["foo","baz"]
- 2
+ 3
配列の場合はインデックスで表されます(jqのパス表現と同じ)。
$ cat a.json
{"foo": ["a", "b", {"c": 1}]}
$ cat b.json
{"foo": ["a", "b", {"c": 2}]}
$ jd a.json b.json
@ ["foo",2,"c"]
- 1
+ 2
$ cat a.json
{"foo": ["a", "b", {"c": 1}]}
$ cat c.json
{"foo": ["a", "b"]}
$ jd a.json c.json
@ ["foo",2]
- {"c":1}
-color
で差分に色を付けられます。差分が多いときは色がある方が見やすいですね。
YAMLの差分も表示可能
さらに、JSONだけでなくYAMLにも対応しています。マニフェストの変更点を確認するのに便利そうです。
$ cat a.yaml
foo:
bar: 1
baz: 2
$ cat b.yaml
foo:
bar: 1
baz: 3
$ jd -yaml a.yaml b.yaml
@ ["foo","baz"]
- 2
+ 3
ファイルのパッチ
2つのJSONの差分表示だけでなく、JSONに差分を適用して変更することも可能です。
JSON間の差分を記録して、別のJSONに適用することもできます。
$ cat a.json
{"foo": {"bar": 1, "baz": 2}}
$ echo diff.patch
diff.patch
$ jd -p diff.patch a.json
{"foo":{"bar":2,"baz":2}}
ただし、diffの元となる値が食い違うとエラーが発生するので注意が必要です1。
$ cat a.json
{"foo": {"bar": 1, "baz": 2}}
$ cat diff.patch
@ ["foo", "bar"]
- 4
+ 2
$ jd -p diff.patch a.json
2022/09/10 10:23:33 found 1 at [foo bar]: expected 4
おわりに
以上、jd
でJSONのdiffを取得する方法の紹介でした。
ちょうど痒い所に手が届くので、jq
、yq
にならんでこのツールには今後たくさんお世話になると思います。
-
差分適用という意味では安全な機構だと思います。 ↩