1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

jqのマニュアルを読み込んでみる その1(基本的な文法編)

Last updated at Posted at 2021-02-06

はじめに

UNIX/Linuxコマンドで有名なテキスト処理系のコマンドjq, grep, awk, sedなどがありますが、
使うとき毎回毎回調べながら使っているので、もっと即興で使いこなせるようになればすごく作業効率が上がるのでないかと思い、これらのコマンドのマニュアルを眺めながら1から勉強してみようと思いました。
その第一回目はjqですが、jqだけでも膨大な量のマニュアルでした笑。
今回はjsonをフィルタリングしたり、整形したりする際の基本的な文法だけを学んでいきます。

環境

システムのバージョン:macOS 10.15.7 (19H2)
カーネルのバージョン:Darwin 19.6.0
jqのバージョン    :jq-1.6

参考文献

man jq

Filter系

そのまま使う

tmp.json
{"message":"Hello World", "colors":["yellow","red","blue"],"members":[{"name":"Tom","age":20},{"name":"Bob","age":31}]}
cat tmp.json | jq 
cat tmp.json | jq '.' # 同じ出力
{
  "message": "Hello World",
  "colors": [
    "yellow",
    "red",
    "blue"
  ],
  "members": [
    {
      "name": "Tom",
      "age": 20
    },
    {
      "name": "Bob",
      "age": 31
    }
  ]
}

この時の.は入力されたjsonの一番トップレベルの階層を表します。
つまり、入力されたjsonそのものです。

Objectを扱う

キーを指定する(その1)

tmp.json
{"message":"Hello World", "colors":["yellow","red","blue"],"members":[{"name":"Tom","age":20},{"name":"Bob","age":31}]}
cat tmp.json | jq '.message'
"Hello World"

キー"message"に対応する値"Hello World"だけを取り出しました。

cat tmp.json | jq '.hoge'
null

存在しないキーを選択するとnullが返ります。

キーを指定する(その2)

tmp.json
{"message":"Hello World", "colors":["yellow","red","blue"],"members":[{"name":"Tom","age":20},{"name":"Bob","age":31}]}
cat tmp.json | jq '.["members"]'
[
  {
    "name": "Tom",
    "age": 20
  },
  {
    "name": "Bob",
    "age": 31
  }
]

このように["キー名"]でも取り出せます。
.members.["members"] は同じ意味ですね。

値だけ列挙する

tmp.json
{"message":"Hello World", "colors":["yellow","red","blue"],"members":[{"name":"Tom","age":20},{"name":"Bob","age":31}]}
cat tmp.json | jq '.[]'
"Hello World"
[
  "yellow",
  "red",
  "blue"
]
[
  {
    "name": "Tom",
    "age": 20
  },
  {
    "name": "Bob",
    "age": 31
  }
]

複数キーを指定する

tmp.json
{"message":"Hello World", "colors":["yellow","red","blue"],"members":[{"name":"Tom","age":20},{"name":"Bob","age":31}]}
cat tmp.json | jq '.message, .colors'
"Hello World"
[
  "yellow",
  "red",
  "blue"
]

カンマ,で複数のキーを指定できます。

Arrayを扱う

Arrayの中身を列挙

tmp.json
{"message":"Hello World", "colors":["yellow","red","blue"],"members":[{"name":"Tom","age":20},{"name":"Bob","age":31}]}
cat tmp.json | jq '.colors'
[
  "yellow",
  "red",
  "blue"
]

このcolorsの3つの要素を列挙する形で取り出したい時は、

cat tmp.json | jq '.colors[]'
"yellow"
"red"
"blue"

.colorsだけだとリストそのものを表示するのに対して、
[]を後ろにつけることによってリストの中身を全て列挙するようになります。

Arrayからn番目の要素

tmp.json
{"message":"Hello World", "colors":["yellow","red","blue"],"members":[{"name":"Tom","age":20},{"name":"Bob","age":31}]}
cat tmp.json | jq '.members[0]'
{
  "name": "Tom",
  "age": 20
}

.members[0]で0番目の要素を取り出しました。

cat tmp.json | jq '.members[2]'
null

存在しない要素番号を指定するとnullが返ります。

cat tmp.json | jq '.colors[-1]'
"blue"

負の数を使うことで後ろから数えて1番目を取り出します。
この時"yellow"は前から数えても後ろから数えても0番目であると考えるとわかりやすいかと思います。

cat tmp.json | jq '.colors[-3]'
cat tmp.json | jq '.colors[-4]'
"yellow"
null

"yellow"の前には何も存在しないのでnullが返ります。

Arrayから任意のキーを指定して表示

tmp.json
{"message":"Hello World", "colors":["yellow","red","blue"],"members":[{"name":"Tom","age":20},{"name":"Bob","age":31}]}
cat tmp.json | jq '.members[].name'
"Tom"
"Bob"

membersのように入れ子になった構造で、nameだけ取り出したい時は上記のようにします。

Arrayから取り出す範囲を指定する(Slice)

tmp.json
["a","b","c","d","e"]
cat tmp.json | jq '.[1:3]'
cat tmp.json | jq '.[:3]'
cat tmp.json | jq '.[2:]'
cat tmp.json | jq '.[-3:-1]'
["b","c"]
["a","b","c"]
["c","d","e"]
["c","d"]

指定したキーがArrayでなくてもエラーにしない

tmp.json
{"message":"Hello World", "colors":["yellow","red","blue"],"members":[{"name":"Tom","age":20},{"name":"Bob","age":31}]}
cat tmp.json | jq '.message[]'
cat tmp.json | jq '.message[]?'
jq: error (at <stdin>:1): Cannot iterate over string ("Hello World")
(何も表示されない)

上の場合だと、messageの値はKey/Value ObjectでもArrayでもないのでエラーになりますが、
下の場合はエラーにしません。

Pipe

tmp.json
{"message":"Hello World", "colors":["yellow","red","blue"],"members":[{"name":"Tom","age":20},{"name":"Bob","age":31}]}
cat tmp.json | jq '.members[] | .name'
cat tmp.json | jq '.members[].name' # 同じ
"Tom"
"Bob"

UNIX/Linuxの | とイメージ的には同じですね。
これだとあんまり意味ありませんね笑

条件指定

cat tmp.json | jq '.members[] | select (.name == "Bob")'
{
  "name": "Bob",
  "age": 31
}

上記のような関数を用いて複雑な条件指定をする時に使用したりします。

一括置換

cat tmp.json | jq '.members[] | .age + 5'
25
36

Objectリストの要素を一括置換したりするときとかにも使えます。

再帰検索

tmp.json
{"a":{"b":{"c":{"a":"e"}}}}
cat tmp.json | jq '..'
{
  "a": {
    "b": {
      "c": {
        "d": "e"
      }
    }
  }
}
{
  "b": {
    "c": {
      "d": "e"
    }
  }
}
{
  "c": {
    "a": "e"
  }
}
{
  "a": "e"
}
"e"

ここから"a"がキーのものを取り出します。

cat tmp.json | jq '.. | .a?'
{
  "b": {
    "c": {
      "a": "e"
    }
  }
}
null
null
"e"

nullも消します。

cat tmp.json | jq '.. | .a? | select(. != null)’
{
  "b": {
    "c": {
      "a": "e"
    }
  }
}
"e"

Pipe気持ちいいですね笑

Operation系

数値の計算

tmp.json
{"a": 7}
cat tmp.json | jq '.a + 1'
cat tmp.json | jq '.a > 1'
8
true

基本的なプログラミング言語にあるような、四則+剰余演算, 比較演算はできます。

tmp.json
[1,2,3,4,5,6]
cat tmp.json | jq '.[] + 1'
2
3
4
5
6
7

リストを一括計算もできます。

リストの加算

tmp.json
{"a" : [1,2], "b" : [2,3]}
cat tmp.json | jq '.a + .b'
[1,2,1,3]

文字列の加算

tmp.json
{"FirstName" : "Hanako", "LastName" : "Tanaka"}
jq '.FirstName + " " +.LastName'
"Hanako Tanaka"

文字列の分割

tmp.json
{"text": "Nothing in life is to be feared. It is only to be understood."}
cat tmp.json | jq '.text / " "'
[
  "Nothing",
  "in",
  "life",
  "is",
  "to",
  "be",
  "feared.",
  "It",
  "is",
  "only",
  "to",
  "be",
  "understood."
]

半角スペースを区切り文字として、文字列全体を分割してリスト化しています。

今回はここまで

jq便利すぎる!!
次回はもっと複雑な操作ができる関数や、if文などをやっていくかなーと思います。

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?