シェルスクリプトとjqコマンドでJSONをループして中身を取り出す
JSON の操作なら jq コマンドで十分なのですが、シェルの中で JSON をいい感じに扱いたい時ってありますよね。
配列の中から特定のキーの値を抜き出す。
そんなイメージの処理を書きたい時です。
「いやいや、それでも jq コマンドで一発でしょ」
って感じになると思いますが、その過程で別のキーの値も参照したいとか、結局は行単位で自由に操作したいケースってあると思うのですよね。
今回は、シェルの中で JSON の配列の 1 行 1 行を抜き出す処理を紹介します。
jqコマンドで特定のキーの値を抜き出す
純粋に特定のキーの値を抜き出してくるだけなら、確かに jq コマンドで事足ります。
値のダブルクォーテーションも除去するならこんな感じですね。
仮に、下記のファイルを rira.json とします。
{
"name": "リラックマ",
"color": "brown"
}
{
"name": "コリラックマ",
"color": "white"
}
{
"name": "キイロイトリ",
"color": "yellow"
}
$ cat rira.json | jq -r .[].name
リラックマ
コリラックマ
キイロイトリ
シェルでループする
上記では「name」だけ取得しましたが、シェルでループさせれば「color」を使うこともできます。
JSON のキー項目が増えれば増えるほど 1 行ずつ処理した方が楽です。
jq コマンドでも強引にできそうな部分はありますが。
例えばこれだと、う~ん微妙・・・。
$ cat rira.json | jq -r '.[].name,.[].color'
リラックマ
コリラックマ
キイロイトリ
brown
white
yellow
これだと name と color が順番に出力されるようになったので、もう少し応用すれば利用価値がありそうでしょうか。
$ cat rira.json | jq -r '.[] | .name,.color'
リラックマ
brown
コリラックマ
white
キイロイトリ
yellow
っと、jq でも頑張ればなんとかできそうですが、シェルでループさせた方が楽なのは間違いありません。
シェルに置き換えて、1 行ずつ取り出してみましょう。
#!/bin/sh
JSON=`cat rira.json`
JSON_LEN=`echo ${JSON} | jq length`
for i in `seq 0 $((${JSON_LEN} - 1))`; do
row=`echo ${JSON} | jq .[${i}]`
echo ${row}
name=`echo ${row} | jq -r .name`
color=`echo ${row} | jq -r .color`
echo "name: ${name}, color: ${color}"
done
実行してみるとこんな感じの結果になります。
{ “name”: “リラックマ”, “color”: “brown” }
name: リラックマ, color: brown
{ “name”: “コリラックマ”, “color”: “white” }
name: コリラックマ, color: white
{ “name”: “キイロイトリ”, “color”: “yellow” }
name: キイロイトリ, color: yellow
まとめ
シェルスクリプトで、JSON ファイルを読み込んで中身を出力してみました。
jq コマンドを応用すれば、もっと多くの JSON 操作ができますが、純粋にシェルで活用した方が便利な場合も多いです。
ワンライナーでカッコよく書ければベターですが、複数行でも簡潔にわかりやすい方がベストです。
Github Actions でワークフローを定義する際に、シェルを使う機会も増えてくるので、TIPS 的なネタは溜めておきたいですね。
って、CI でそんな複雑なことしたくないのが本音ですが・・・。