jq 快速參考指南

命令列 JSON 處理器,用於格式化、過濾和轉換 JSON 資料。


目錄


什麼是 jq?

jq 是一個輕量級的命令列 JSON 處理器,用來:

  • 格式化 JSON 輸出
  • 提取特定欄位
  • 過濾和轉換 JSON 資料
  • 在 shell 腳本中處理 API 回應

官網https://jqlang.github.io/jq/


安裝

# macOS
brew install jq

# 檢查版本
jq --version

基本語法

jq [選項] '過濾器' [檔案]

# 從檔案讀取
jq '.' data.json

# 從 stdin 讀取
echo '{"name":"Alice"}' | jq '.'
curl https://api.example.com | jq '.'

常用選項

選項 說明 範例
. 原樣輸出(格式化) jq '.'
-r 原始輸出(去除引號) jq -r '.name'
-c 緊湊輸出(單行) jq -c '.'
-S 排序 key jq -S '.'
-e 設定退出碼 jq -e '.error'
-n 不讀取輸入 jq -n '{a:1}'

快速查詢表

1. 基本存取

# 範例資料
echo '{"name":"Alice","age":30,"city":"Taipei"}' > user.json
操作 語法 範例 輸出
格式化 . jq '.' user.json 美化的 JSON
取得欄位 .key jq '.name' user.json "Alice"
去除引號 -r .key jq -r '.name' user.json Alice
多層存取 .key.subkey jq '.address.city' 取得巢狀值
可選存取 .key? jq '.missing?' 不存在時不報錯

2. 陣列操作

# 範例資料
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' > users.json
操作 語法 範例 輸出
第一個元素 .[0] jq '.[0]' users.json {"name":"Alice",...}
最後一個 .[-1] jq '.[-1]' users.json 最後一個元素
切片 .[start:end] jq '.[0:2]' 前兩個元素
所有元素 .[] jq '.[]' users.json 展開陣列
陣列長度 length jq 'length' users.json 2
取得欄位 .[].key jq '.[].name' users.json "Alice" "Bob"

3. 過濾與選擇

# 範例資料
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25},{"name":"Charlie","age":35}]' > users.json
操作 說明 範例
過濾條件 選擇 age > 28 `jq '.[]
判斷相等 選擇 name 為 Alice `jq '.[]
包含字串 name 包含 "li" `jq '.[]
多條件 AND 25 < age < 35 `jq '.[]
多條件 OR age < 25 或 > 35 `jq '.[]
存在判斷 有 email 欄位 `jq '.[]

4. 轉換與建構

操作 語法 範例 輸出
取多個欄位 {key1, key2} jq '{name, age}' user.json {"name":"Alice","age":30}
重新命名 {newKey: .oldKey} jq '{username: .name}' user.json {"username":"Alice"}
建構物件 {key: value} jq '{name: .name, adult: (.age >= 18)}' 建構新物件
建構陣列 [items] jq '[.name, .age]' user.json ["Alice", 30]
Map 轉換 map(expression) jq 'map(.name)' users.json ["Alice","Bob"]
增加欄位 . + {key: value} jq '. + {country: "TW"}' 新增欄位

5. 聚合函數

操作 說明 範例
長度 陣列長度 `jq '.users
鍵列表 取得所有 key jq 'keys' user.json
值列表 取得所有值 `jq '.[]
最小值 最小年齡 `jq '[.[].age]
最大值 最大年齡 `jq '[.[].age]
加總 年齡總和 `jq '[.[].age]
平均 平均年齡 `jq '[.[].age]
排序 排序陣列 jq 'sort' array.json
排序(依欄位) 依 age 排序 jq 'sort_by(.age)' users.json
反轉 反轉陣列 jq 'reverse' array.json
唯一值 去重複 jq 'unique' array.json
分組 依 age 分組 jq 'group_by(.age)'

6. 字串操作

操作 說明 範例
字串連接 連接字串 jq '.firstName + " " + .lastName'
轉大寫 轉大寫 `jq '.name
轉小寫 轉小寫 `jq '.name
分割 分割字串 `jq '.email
測試正則 測試是否符合 `jq '.email
匹配正則 提取匹配內容 `jq '.text
替換 替換第一個 `jq '.name
替換所有 替換所有 `jq '.text
包含 包含判斷 `jq '.name
開頭 開頭判斷 `jq '.name
結尾 結尾判斷 `jq '.name

7. 型別轉換

操作 說明 範例
轉字串 數字轉字串 `jq '.age
轉數字 字串轉數字 `jq '.ageStr
轉陣列 包成陣列 jq '[.name, .age]'
型別檢查 查看型別 `jq '.age

8. 條件判斷

操作 範例
if-then-else jq 'if .age >= 18 then "adult" else "minor" end'
三元運算 `jq '.age >= 18
空值處理 jq '.email // "no-email"'

9. 管道與組合

操作 說明 範例
管道 串接多個操作 `jq '.users
逗號 產生多個輸出 jq '.name, .age'
括號 調整優先順序 jq '(.age + 5) * 2'

實戰範例

範例 1:API 回應處理

# 取得 GitHub API 的 repo 名稱
curl -s https://api.github.com/users/octocat/repos | jq '.[].name'

# 取得前 5 個 repo 的名稱和星數
curl -s https://api.github.com/users/octocat/repos | \
  jq '.[:5] | .[] | {name: .name, stars: .stargazers_count}'

範例 2:過濾 Docker 容器

# 列出所有執行中的容器名稱
docker ps --format json | jq -r '.Names'

# 過濾特定 image 的容器
docker ps -a --format json | jq 'select(.Image | contains("nginx"))'

範例 3:處理 kubectl 輸出

# 取得所有 Pod 名稱
kubectl get pods -o json | jq -r '.items[].metadata.name'

# 取得特定 namespace 的 Pod IP
kubectl get pods -n default -o json | \
  jq -r '.items[] | "\(.metadata.name): \(.status.podIP)"'

# 過濾 Running 狀態的 Pod
kubectl get pods -o json | \
  jq '.items[] | select(.status.phase == "Running") | .metadata.name'

範例 4:處理巢狀 JSON

# 範例 JSON
cat << 'EOF' > data.json
{
  "users": [
    {
      "name": "Alice",
      "contacts": {
        "email": "alice@example.com",
        "phone": "123-456"
      }
    },
    {
      "name": "Bob",
      "contacts": {
        "email": "bob@example.com"
      }
    }
  ]
}
EOF

# 取得所有 email
jq '.users[].contacts.email' data.json

# 取得有 phone 的使用者
jq '.users[] | select(has("contacts") and (.contacts | has("phone")))' data.json

範例 5:轉換資料格式

# 原始資料(陣列)
echo '[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]' | \
  jq 'map({user_id: .id, username: .name})'

# 輸出:
# [
#   {"user_id": 1, "username": "Alice"},
#   {"user_id": 2, "username": "Bob"}
# ]

範例 6:統計與聚合

# 範例資料
cat << 'EOF' > orders.json
[
  {"product": "A", "price": 100, "quantity": 2},
  {"product": "B", "price": 50, "quantity": 5},
  {"product": "A", "price": 100, "quantity": 1}
]
EOF

# 計算總金額
jq '[.[] | .price * .quantity] | add' orders.json
# 輸出:550

# 依產品分組
jq 'group_by(.product)' orders.json

# 計算每個產品的總數量
jq 'group_by(.product) | map({product: .[0].product, total: map(.quantity) | add})' orders.json

範例 7:組合多個條件

# 複雜過濾
cat << 'EOF' > products.json
[
  {"name": "Laptop", "price": 50000, "stock": 5, "category": "electronics"},
  {"name": "Mouse", "price": 500, "stock": 0, "category": "electronics"},
  {"name": "Book", "price": 300, "stock": 10, "category": "books"}
]
EOF

# 找出有庫存且價格 < 1000 的電子產品
jq '.[] | select(.category == "electronics" and .stock > 0 and .price < 1000)' products.json

範例 8:CSV 輸出

# JSON 轉 CSV
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' | \
  jq -r '.[] | [.name, .age] | @csv'

# 輸出:
# "Alice",30
# "Bob",25

# 加上標題
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' | \
  jq -r '["name","age"], (.[] | [.name, .age]) | @csv'

# 輸出:
# "name","age"
# "Alice",30
# "Bob",25

範例 9:環境變數注入

# 使用環境變數
export USERNAME="Alice"
jq -n --arg name "$USERNAME" '{user: $name, timestamp: now}'

# 輸出:
# {
#   "user": "Alice",
#   "timestamp": 1234567890
# }

範例 10:多檔案處理

# 合併多個 JSON 檔案
jq -s '.' file1.json file2.json

# 從多個檔案提取特定欄位
jq -s 'map(.name)' file1.json file2.json

常用組合技巧

1. 格式化 + 取欄位

curl -s https://api.example.com | jq -r '.data[] | .name'

2. 過濾 + 排序 + 限制數量

jq '[.[] | select(.age > 25)] | sort_by(.age) | .[0:5]' users.json

3. 多欄位輸出(表格式)

jq -r '.[] | "\(.name)\t\(.age)\t\(.city)"' users.json

4. 條件轉換

jq '.[] | {name, status: (if .age >= 18 then "adult" else "minor" end)}' users.json

除錯技巧

1. 顯示錯誤訊息

jq -e '.error != null' response.json && echo "有錯誤"

2. 美化輸出以檢查結構

cat messy.json | jq '.' > pretty.json

3. 顯示型別

jq '.field | type' data.json

最佳實踐

1. 使用 -r 移除引號

# ❌ 不好的做法:保留引號
jq '.name' data.json
# 輸出:"Alice"

# ✅ 好的做法:直接輸出值
jq -r '.name' data.json
# 輸出:Alice

2. 使用 ? 避免錯誤

# ❌ 不好的做法:欄位不存在時報錯
jq '.missing_field' data.json
# 錯誤:Cannot index string with string "missing_field"

# ✅ 好的做法:使用可選存取
jq '.missing_field?' data.json
# 輸出:null(不報錯)

3. 先測試小範例再處理大檔案

# ✅ 好的做法:先用 head 測試
head -n 5 large.json | jq '.[] | select(.status == "active")'

# 確認正確後再處理完整檔案
jq '.[] | select(.status == "active")' large.json

4. 使用 -c 壓縮輸出給其他程式使用

# ❌ 不好的做法:美化輸出不適合管線傳遞
jq '.' data.json | wc -l

# ✅ 好的做法:壓縮輸出方便處理
jq -c '.' data.json | wc -l

5. 複雜查詢分段測試

# ✅ 好的做法:逐步建構查詢
# 第一步:確認資料結構
jq '.' data.json

# 第二步:測試過濾
jq '.[] | select(.age > 25)' data.json

# 第三步:加入欄位選擇
jq '.[] | select(.age > 25) | {name, age}' data.json

6. 使用變數提升可讀性

# ❌ 不好的做法:重複的表達式
jq '.items[] | select(.price > 100) | {name: .name, discount: (.price * 0.1)}' data.json

# ✅ 好的做法:使用變數
jq '.items[] | select(.price > 100) | . as $item | {name: $item.name, discount: ($item.price * 0.1)}' data.json

7. 錯誤處理最佳實踐

# ✅ 結合 -e 選項檢查錯誤
if jq -e '.error' response.json > /dev/null 2>&1; then
  echo "API 回應包含錯誤"
  jq -r '.error.message' response.json
else
  echo "API 回應正常"
  jq -r '.data' response.json
fi

8. 效能優化建議

# ❌ 不好的做法:多次讀取同一個檔案
name=$(jq -r '.name' data.json)
age=$(jq -r '.age' data.json)
city=$(jq -r '.city' data.json)

# ✅ 好的做法:一次讀取取得多個值
read name age city < <(jq -r '.name, .age, .city' data.json)

快速備忘

最常用的 5 個指令

# 1. 格式化 JSON
jq '.' data.json

# 2. 取欄位(去引號)
jq -r '.name' data.json

# 3. 取陣列所有元素的某欄位
jq -r '.[].name' data.json

# 4. 過濾
jq '.[] | select(.age > 25)' data.json

# 5. 建構新物件
jq '{username: .name, years: .age}' data.json

線上測試工具


常見錯誤

錯誤 1:忘記使用 -r

# ❌ 錯誤:輸出包含引號
jq '.name' user.json
# 輸出:"Alice"

# ✅ 正確:使用 -r 去除引號
jq -r '.name' user.json
# 輸出:Alice

錯誤 2:忘記用引號包住 jq 表達式

# ❌ 錯誤:shell 會把 | 當作管道
jq .users | .[0] data.json

# ✅ 正確:用引號包住
jq '.users | .[0]' data.json

錯誤 3:陣列展開後要逐一處理

# ❌ 錯誤
jq '.[]' users.json | grep name  # 無法用 grep

# ✅ 正確
jq -r '.[].name' users.json | grep Alice  # 用 jq 先提取

總結

需求 語法
格式化 jq '.'
取欄位 jq -r '.field'
取陣列元素 jq '.[0]'jq '.[]'
過濾 jq '.[] | select(.age > 25)'
轉換 jq '.[] | {new: .old}'
排序 jq 'sort_by(.field)'
長度 jq 'length'
加總 jq 'map(.price) | add'

核心概念

  • . = 目前位置
  • | = 管道傳遞
  • [] = 陣列展開
  • select() = 過濾
  • map() = 轉換每個元素

建議:開始時只用 ..field.[]select(),熟練後再用進階功能。


建立日期:2025-10-15 最後更新:2025-11-18

🔗相關文章