← 全部文章

jq 教學:過濾與轉換 JSON

實用 jq 教學:安裝、美化與壓縮、選欄位、用 select 過濾陣列、用 map 轉換,並附可直接複製貼上的命令食譜。

jq 是切片、過濾與轉換 JSON 的標準命令列工具。它把一行命令變成處理 API 回應、log 檔案與設定的強大查詢語言。本教學涵蓋安裝、你每天會用到的核心 filter,以及一組針對最常見實際任務的可複製貼上 recipe。

什麼是 jq?

jq 從檔案或標準輸入讀取 JSON,套用一個 filter,再把 JSON(或純文字)寫到標準輸出。預設會格式化輸出,而且絕不會把你的資料送到任何地方 —— 它是個本地端二進位檔,處理敏感 payload 也很合適。

安裝 jq

# macOS
brew install jq

# Debian / Ubuntu
sudo apt-get install jq

# Windows (winget or choco)
winget install jqlang.jq

# 驗證
jq --version

Identity Filter:隨手格式化

最簡單的 filter . 會原樣回傳輸入 —— 這就讓 jq 成了一個即時格式化工具:

# 格式化一個檔案
jq . data.json

# 格式化 curl 的回應
curl -s https://api.example.com/users | jq .

# 反過來壓縮(緊湊輸出)
jq -c . data.json

選取欄位

.key 鑽進物件,用 [] 鑽進陣列:

echo '{"user":{"name":"Ada","age":36}}' | jq '.user.name'
# "Ada"

# 陣列的全部元素
echo '[{"id":1},{"id":2}]' | jq '.[]'
# {"id":1}
# {"id":2}

# 從每個陣列元素取出一個欄位
echo '[{"id":1,"name":"Ada"},{"id":2,"name":"Bob"}]' | jq '.[].name'
# "Ada"
# "Bob"

# 用 -r 去掉 JSON 的引號(raw output)
jq -r '.[].name' users.json

用 select 過濾

# 只保留符合條件的物件
echo '[{"name":"Ada","active":true},{"name":"Bob","active":false}]' \
  | jq '.[] | select(.active == true)'
# {"name":"Ada","active":true}

# 數值比較
jq '.[] | select(.age > 30)' users.json

用 map 和物件建構來變形

# 把每個元素重新組合成新物件
echo '[{"id":1,"name":"Ada","email":"a@x.com"}]' \
  | jq 'map({ userId: .id, label: .name })'
# [{"userId":1,"label":"Ada"}]

# 抽出一個扁平的值列表
jq '[.[].email]' users.json     # ["a@x.com", ...]

# 用 | 把 filter 串起來
jq '.items | map(.price) | add' order.json   # 所有價格之和

常用 Recipe

任務指令
格式化jq . file.json
壓縮jq -c . file.json
取一個欄位jq '.data.token' resp.json
Raw 字串(不帶引號)jq -r '.token' resp.json
計算陣列長度jq '. | length' list.json
物件的所有 keyjq 'keys' obj.json
過濾行jq '.[] | select(.active)'
依欄位排序jq 'sort_by(.age)'
加總一個欄位jq '[.[].amount] | add'
排序物件的 keyjq --sort-keys . file.json
驗證(透過 exit code)jq empty file.json

重塑物件:to_entries / from_entries

jq 裡兩個最有用的物件形狀變換工具:

# 重新命名每個 key(這裡轉小寫)
echo '{"Name":"Ada","Active":true}' \
  | jq 'with_entries(.key |= ascii_downcase)'
# → {"name":"Ada","active":true}

# 丟掉值為 null 的 key
jq 'with_entries(select(.value != null))' file.json

# 物件 ⇄ 鍵值對陣列
jq 'to_entries' file.json     # → [{"key":"name","value":"Ada"}, ...]
jq 'from_entries' pairs.json  # → {"name":"Ada", ...}

插值與輸出格式:\(.x)@csv@json@base64

jq 內建字串插值與 格式字串,可以把 JSON 轉成其他格式:

# 在引號字串裡做字串插值
jq -r '"\(.user) bought \(.items|length) items"' order.json

# 每個物件一列 CSV
jq -r '.[] | [.id, .name, .total] | @csv' orders.json

# 內聯 JSON 給 shell 用(轉義過的字串字面值)
jq -r '.user | @json' record.json

# Base64 編碼一個值(處理 token / data URI 很方便)
jq -r '.payload | @base64' message.json
# 解碼這邊:較新版 jq 支援 @base64d

用 jq 驗證 JSON

因為 jq 遇到非法輸入時 exit code 非零,jq empty file.json 是腳本與 CI 裡乾淨俐落的合法性檢查 —— 更多驗證方法見 如何驗證 JSON

什麼時候瀏覽器工具更快

jq 在腳本與 pipeline 裡很出彩,但對於一次性的小事 —— 格式化貼過來的回應、檢視一個陌生的結構、修復壞掉的 JSON —— 瀏覽器工具不用安裝、也不用做 shell 轉義:

常見問題

怎麼用 jq 格式化 JSON?

執行 jq . file.json —— identity filter . 回傳輸入,而 jq 預設會格式化輸出。要緊湊輸出就用 -c

怎麼用 jq 抽出單一欄位?

用路徑 filter,例如 jq '.data.token',再加上 -r 就能拿到不帶引號的 raw 值。

怎麼用 jq 過濾 JSON 陣列?

.[] 走訪,再用 select(),例如 jq '.[] | select(.active == true)'

jq 能驗證 JSON 嗎?

可以 —— jq empty file.json 解析輸入,如果非法就以非零 exit code 結束,在 CI 裡很實用。詳情見 如何驗證 JSON

繼續閱讀