動機

在bash想處理json的好工具

basic

  • .就是目前的input
  • .<name>會取對應key的value
  • {obj}[0]這是取array的第零項
  • {obj}[i:j]這是slice第i項到第j-1項的array
  • {obj}[]會iterate所有項目
    • array就是每個item
    • obj就是無視key,把每個value走過一次
  • [<expr>] {<expr>}分別做出array與json object
  • <expr0> | <expr> as $var | <expr2>設定$var<expr>的值,pipe後面的點是<expr0>的值

例子

假設我們想把

[
    {
      "name":"Test Value",
      "timer":[
          { "datetime":"08/30/2017 16:33:35", "value":"625" },
          { "datetime":"08/30/2017 16:22:38", "value":"240" }
      ]
    },
    {
      "name":"Test Value 2",
      "timer":[
          { "datetime":"08/30/2017 16:07:38", "value":"432" },
          { "datetime":"08/30/2017 15:59:07", "value":"1355" }
      ]
    }
]

變成

[
  [
    "Test Value",
    "08/30/2017 16:33:35"
  ],
  [
    "Test Value",
    "08/30/2017 16:22:38"
  ]
]
[
  [
    "Test Value 2",
    "08/30/2017 16:07:38"
  ],
  [
    "Test Value 2",
    "08/30/2017 15:59:07"
  ]
]

所以要做的是

  1. 拿name
  2. iterate每個timer去拿datetime
  3. datetime與name組在一起

下面一步一步的code

  • .[]
    • 先走每個值
  • .[] | .name as $name
    • 取name
  • .[] | .name as $name | .timer[]
    • 取timer走每個值
  • .[] | .name as $name | .timer[] | .datetime
    • 取timer走每個值
  • .[] | .name as $name | .timer[] | [$name, .datetime]
    • 把tiemr與datetime合起來
  • .[] | .name as $name | [.timer[] | [$name, .datetime]]
    • 最後把timer的loop包起來

這個例子因為把不同level的資料和在一起,所以要變數把不同level的東西存好 才有辦法在後面需要時去用

所以怎麼看jq的咒語?

  • 順著原本的json架構去看
  • 分pipe去看現在的.是誰
  • 遇到建構array或obj的部分要對好原本json的位置去看裡面是在建構什麼

faltten

如果要把

[
  [
    "Test Value",
    "08/30/2017 16:33:35"
  ],
  [
    "Test Value",
    "08/30/2017 16:22:38"
  ]
]
[
  [
    "Test Value 2",
    "08/30/2017 16:07:38"
  ],
  [
    "Test Value 2",
    "08/30/2017 15:59:07"
  ]
]

變成

[
  [
    "Test Value",
    "08/30/2017 16:33:35"
  ],
  [
    "Test Value",
    "08/30/2017 16:22:38"
  ]
  [
    "Test Value 2",
    "08/30/2017 16:07:38"
  ],
  [
    "Test Value 2",
    "08/30/2017 15:59:07"
  ]
]

可以用faltten

faltten(1) 這樣就能攤平一層

map, reduce

就是map與reduce,不過要注意.代表什麼

  • map
    • 括號中的點是array或obj被走到的value
  • reduce
    • 第一個點是整個input
    • 第二個點是acc(累積的項目)

[1,2,3]變成[11,12,13]

jq 'map(.+10)'
jq 'reduce .[] as $i ([]; . += [($i+10)])'

else

jq還能

  • regex
  • if-else
    • 可以判斷type,數字,字母,奇偶
  • while
  • 自訂function與recurse operator
  • math(像三角函數)
  • 許多builtin function

Ref

jq get each value in array with parent jq Manual