jq — JSON 查詢與轉換
選擇性閱讀規則
請從以下文件開始:
references/senior-master-standard.mdreferences/usage-routing.mdreferences/quality-checklist.md
然後僅載入與使用者實際任務相關的繼承文件、腳本、資源或範例。
概述
jq 是用於查詢和重塑 JSON 的標準 CLI 工具。此技能涵蓋實用、專家級的用法:過濾深層巢狀資料、轉換結構、聚合數值,以及將 jq 組合進 Shell 管線中。每個範例都可以直接複製貼上以用於實際工作流程。
何時使用此技能
- 用於解析來自 API、CLI 工具(AWS、GitHub、kubectl、docker)或日誌檔案的 JSON 輸出時
- 用於轉換 JSON 結構(重新命名鍵、扁平化陣列、分組記錄)時
- 當使用者需要在 bash 腳本或單行程式中使用
jq時 - 當需要解釋複雜的
jq表達式時
運作方式
jq 接受一個過濾器表達式,並將其應用於 JSON 輸入。過濾器透過管線符號 (|) 組合,jq 原生支援陣列、物件、字串、數字、布林值和 null。
基本選取
# 提取一個欄位
echo '{"name":"alice","age":30}' | jq '.name'
# "alice"
# 巢狀存取
echo '{"user":{"email":"[email protected]"}}' | jq '.user.email'
# 陣列索引
echo '[10, 20, 30]' | jq '.[1]'
# 20
# 陣列切片
echo '[1,2,3,4,5]' | jq '.[2:4]'
# [3, 4]
# 所有陣列元素
echo '[{"id":1},{"id":2}]' | jq '.[]'
使用 select 過濾
# 僅保留符合條件的元素
echo '[{"role":"admin"},{"role":"user"},{"role":"admin"}]' \
| jq '[.[] | select(.role == "admin")]'
# 數值比較
curl -s https://api.github.com/repos/owner/repo/issues \
| jq '[.[] | select(.comments > 5)]'
# 測試欄位是否存在且非 null
jq '[.[] | select(.email != null)]'
# 組合條件
jq '[.[] | select(.active == true and .score >= 80)]'
映射與轉換
# 從每個陣列元素提取一個欄位
echo '[{"name":"alice","age":30},{"name":"bob","age":25}]' \
| jq '[.[] | .name]'
# ["alice", "bob"]
# 縮寫:map()
jq 'map(.name)'
# 為每個元素建立新物件
jq '[.[] | {user: .name, years: .age}]'
# 新增一個計算後的欄位
jq '[.[] | . + {senior: (.age > 28)}]'
# 重新命名鍵
jq '[.[] | {username: .name, email_address: .email}]'
聚合與 Reduce
# 加總所有值
echo '[1, 2, 3, 4, 5]' | jq 'add'
# 15
# 計算物件中某個欄位的總和
jq '[.[].price] | add'
# 計算元素數量
jq 'length'
# 最大值 / 最小值
jq 'max_by(.score)'
jq 'min_by(.created_at)'
# reduce:自訂累積器
echo '[1,2,3,4,5]' | jq 'reduce .[] as $x (0; . + $x)'
# 15
# 按欄位分組
jq 'group_by(.department)'
# 依分組計數
jq 'group_by(.status) | map({status: .[0].status, count: length})'
字串插值與格式化
# 字串插值
jq -r '.[] | "\(.name) 是 \(.age) 歲"'
# 格式化為 CSV(無標題)
jq -r '.[] | [.name, .age, .email] | @csv'
# 格式化為 TSV
jq -r '.[] | [.name, .score] | @tsv'
# URL 編碼一個值
jq -r '.query | @uri'
# Base64 編碼
jq -r '.data | @base64'
處理鍵與路徑
# 列出所有頂層鍵
jq 'keys'
# 檢查鍵是否存在
jq 'has("email")'
# 刪除一個鍵
jq 'del(.password)'
# 從每個元素刪除巢狀鍵
jq '[.[] | del(.internal_id, .raw_payload)]'
# 遞迴下降:在樹中的任何位置尋找某個鍵的所有值
jq '.. | .id? // empty'
# 取得所有葉子路徑
jq '[paths(scalars)]'
條件判斷與錯誤處理
# if-then-else
jq 'if .score >= 90 then "A" elif .score >= 80 then "B" else "C" end'
# 替代運算子:如果為 null 或 false 則使用備用值
jq '.nickname // .name'
# try-catch:跳過錯誤而非停止
jq '[.[] | try .nested.value catch null]'
# 使用 // empty 抑制 null 輸出
jq '.[] | .optional_field // empty'
實用的 Shell 整合
# 從檔案讀取
jq '.users' data.json
# 緊湊輸出(無空白)以便進一步管道處理
jq -c '.[]' records.json | while IFS= read -r record; do
echo "正在處理:$record"
done
# 將 Shell 變數傳入 jq
STATUS="active"
jq --arg s "$STATUS" '[.[] | select(.status == $s)]'
# 傳入數字
jq --argjson threshold 42 '[.[] | select(.value > $threshold)]'
# 將多個 JSON 行吞入一個陣列
jq -s '.' records.ndjson
# 多個檔案:將所有檔案吞入一個陣列
jq -s 'add' file1.json file2.json
# 從命令安全地進行管線處理
kubectl get pods -o json | jq '.items[] | {name: .metadata.name, status: .status.phase}'
# GitHub CLI:提取 PR 編號
gh pr list --json number,title | jq -r '.[] | "\(.number)\t\(.title)"'
# AWS CLI:列出執行中的執行個體 ID
aws ec2 describe-instances \
| jq -r '.Reservations[].Instances[] | select(.State.Name=="running") | .InstanceId'
# Docker:顯示容器名稱和映像檔
docker inspect $(docker ps -q) | jq -r '.[] | "\(.Name)\t\(.Config.Image)"'
進階模式
# 將物件陣列轉置為物件陣列
# 輸入:{"names":["a","b"],"scores":[10,20]}
jq '[.names, .scores] | transpose | map({name: .[0], score: .[1]})'
# 展開一層
jq 'flatten(1)'
# 依欄位去重
jq 'unique_by(.email)'
# 排序、去重並重新索引
jq '[.[] | .name] | unique | sort'
# walk:遞迴地對每個節點套用轉換
jq 'walk(if type == "string" then ascii_downcase else . end)'
# env:在 jq 內部讀取環境變數
export API_KEY=secret
jq -n 'env.API_KEY'
最佳實踐
- 當將
jq結果傳遞給 Shell 變數或其他命令時,務必使用-r(原始輸出)以去除 JSON 字串的引號 - 使用
--arg/--argjson安全地注入 Shell 變數——絕不要直接在過濾器字串中插值 Shell 變數 - 為了可讀性,優先使用
map(f)而非[.[] | f] - 對於換行分隔的 JSON 管線,使用
-c(緊湊);為了人類可讀的除錯則省略它 - 在嵌入腳本之前,先用
jq -n和字面輸入互動式測試過濾器 - 使用
empty來丟棄不需要的元素,而非過濾為null
安全性與注意事項
jq預設為唯讀——它無法寫入檔案或執行命令- 避免將不受信任的 JSON 欄位值直接嵌入 Shell 命令;務必使用引號或
--arg
常見陷阱
-
問題:
jq輸出null而非預期值 解決方案: 檢查鍵名稱是否有拼寫錯誤;使用keys檢查實際欄位名稱。請記住 JSON 區分大小寫。 -
問題: 輸出中的數字被用引號括起來成為字串 解決方案: 注入數值時使用
--argjson而非--arg。 -
問題: 過濾器在終端機中有效,但在腳本中失敗 解決方案: 確保過濾器字串在 Shell 中使用單引號以防止變數展開。範例:使用
jq '.field'而非jq ".field"。 -
問題:
add在空陣列上返回null解決方案: 使用add // 0或add // ""來提供備用預設值。 -
問題: 串流處理大型檔案很慢 解決方案: 對於非常大的檔案,使用
jq --stream或改用jstream/gron。
相關技能
@bash-pro— 將 jq 呼叫包裝在穩健的 Shell 腳本中@bash-linux— 一般 Shell 管道模式@github-automation— 將 jq 與 GitHub CLI JSON 輸出一起使用
限制
- 僅在任務明確符合上述範圍時使用此技能。
- 不要將輸出視為環境特定驗證、測試或專家審查的替代品。
- 如果缺少所需的輸入、權限、安全邊界或成功標準,請停下來並要求澄清。