Sổ tay kỹ thuật

jq và yq – lọc, biến đổi JSON và YAML trên dòng lệnh

cheatsheet#jq#yq#json#yaml· cập nhật 2026-11-06

Tra nhanh filter jq (select, map, to_entries, @tsv, --arg) để xử lý output API/JSON và yq bản mikefarah để đọc, sửa file YAML như inventory Ansible hay manifest Kubernetes.

Sửa trang này
Mục lục

Ví dụ dùng file devices.json dạng {"devices": [{"hostname", "platform", "mgmt_ip", "status", "interfaces": [{"name", "oper", "mtu"}]}]}. Đã chạy thử với jq 1.6 và yq v4.54 (mikefarah). Có hai công cụ cùng tên yq: bản mikefarah (Go, một binary, yq --version có chữ mikefarah) và bản kislyuk (Python, bọc jq). Trang này dùng bản mikefarah, cú pháp hai bản khác nhau.

jq: đọc và lọc

Mục đích Lệnh
Pretty-print / thu gọn 1 dòng jq . file.json / jq -c . file.json
Chuỗi không có dấu nháy (dùng trong shell) jq -r '.devices[].hostname' devices.json
Lọc theo điều kiện jq -c '.devices[] | select(.platform == "iosxr" and .status == "active")' devices.json
Lấy vài field jq -c '.devices[] | {hostname, mgmt_ip}' devices.json
Field null hoặc thiếu jq -r '.devices[] | select(.mgmt_ip == null) | .hostname' devices.json
Giá trị mặc định khi null .mgmt_ip // "-"
Khớp regex / tiền tố select(.hostname | test("^pe")) / select(.hostname | startswith("pe"))
Mảng con lồng nhau, giữ biến của cha jq -r '.devices[] | .hostname as $h | .interfaces[] | select(.oper == "down") | "\($h) \(.name)"' devices.json
Đếm phần tử jq '.devices | length' devices.json
Danh sách key jq -c '.devices[0] | keys' devices.json
Thoát với mã lỗi nếu kết quả null/false/rỗng (dùng trong script) jq -e '.devices[] | select(.hostname == "pe9")' devices.json

jq: biến đổi

Mục đích Lệnh
Map mảng jq -c '.devices | map(.hostname)' devices.json
Sắp xếp / loại trùng jq -c '.devices | sort_by(.hostname)' devices.json / jq -c '[.devices[].platform] | unique' devices.json
Đếm theo nhóm jq -c '.devices | group_by(.platform) | map({platform: .[0].platform, count: length})' devices.json
Mảng thành object {hostname: ip} jq -c '.devices | map({(.hostname): .mgmt_ip}) | add' devices.json
Duyệt key/value của object to_entries → [{key, value}], ngược lại from_entries
Lọc key của object jq -c '.devices[0] | with_entries(select(.key != "interfaces"))' devices.json
Xoá field jq 'del(.devices[].interfaces)' devices.json
Sửa giá trị theo điều kiện jq '(.devices[] | select(.hostname == "pe2-hcm") | .status) = "active"' devices.json
Cập nhật tại chỗ một nhánh jq '.devices |= map(select(.status == "active"))' devices.json
Gộp object (merge sâu) jq -n '{a: 1} * {b: 2}'
Gộp mảng từ nhiều file jq -s 'add' a.json b.json
Tổng, max, trung bình jq '[.devices[].interfaces[].mtu] | add, max, add/length' devices.json

jq: biến shell và xuất dữ liệu

Mục đích Lệnh
Truyền chuỗi từ shell (an toàn, không ghép chuỗi) jq --arg h "$HOST" '.devices[] | select(.hostname == $h)' devices.json
Truyền số/JSON jq --argjson n 9200 '[.devices[].interfaces[] | select(.mtu > $n) | .name]' devices.json
Ra TSV / CSV jq -r '.devices[] | [.hostname, .platform, (.mgmt_ip // "-")] | @tsv' devices.json / @csv
Nối chuỗi từ mảng jq -r '.devices[] | "\(.hostname)\t\(.interfaces | map(.name) | join(","))"' devices.json
Tạo JSON mới cho body API jq -n --arg h pe3-dng --arg ip 198.51.100.13 '{hostname: $h, mgmt_ip: $ip}'
Xử lý output API curl -s localhost:8000/openapi.json | jq '.paths | keys'

Sửa file JSON "tại chỗ": jq không có -i. Dùng jq '...' f.json > f.tmp && mv f.tmp f.json, hoặc sponge (gói moreutils). Đừng jq ... f.json > f.json: file bị xoá rỗng trước khi jq đọc.

yq (mikefarah): YAML

Mục đích Lệnh
Đọc giá trị yq '.all.children.iosxr.hosts.pe1-hni.ansible_host' hosts.yml
Key có ký tự đặc biệt / lấy từ biến yq '.all.children.iosxr.hosts["pe1-hni"]' hosts.yml
Liệt kê key yq '.all.children.iosxr.hosts | keys | .[]' hosts.yml
Duyệt key/value yq '.all.children.iosxr.hosts | to_entries | .[] | .key + " " + .value.ansible_host' hosts.yml
Sửa và in ra (không ghi file) yq '.all.children.iosxr.vars.ansible_user = "netops"' hosts.yml
Sửa trực tiếp file yq -i '.all.children.iosxr.vars.ansible_user = "netops"' hosts.yml
Gán từ biến môi trường (luôn là chuỗi) HOST=pe3-dng yq '.all.children.iosxr.hosts[strenv(HOST)] = {"ansible_host": "198.51.100.13"}' hosts.yml
Xoá node yq -i 'del(.all.children.iosxr.hosts.pe2-hcm)' hosts.yml
Giá trị mặc định yq '.all.vars.timeout // 30' hosts.yml
Tạo YAML từ đầu yq -n '.a.b = "c"'
YAML sang JSON (1 dòng) yq -o=json -I=0 '.' hosts.yml
JSON sang YAML yq -p=json -o=yaml '.' devices.json
Thoát lỗi nếu không tìm thấy yq -e '.all.vars.ntp_server' hosts.yml
Merge nhiều file (file sau đè file trước) yq ea '. as $item ireduce ({}; . * $item)' base.yml override.yml

Manifest nhiều document (---)

Mục đích Lệnh
Lấy field ở mọi document yq '.metadata.name' deploy.yaml
Chỉ document thoả điều kiện yq 'select(.kind == "Service") | .metadata.name' deploy.yaml
Sửa một document, giữ nguyên các document khác TAG=v2 yq -i '(select(.kind == "Deployment") | .spec.template.spec.containers[0].image) = "netinv:" + strenv(TAG)' deploy.yaml
Sửa image theo tên container yq -i '(.spec.template.spec.containers[] | select(.name == "api") | .image) = "netinv:0.2.0"' deploy.yaml

yq -i 'select(.kind == "Deployment") | .spec.replicas = 2' (không bọc ngoặc vế trái) chỉ in ra document được chọn, và với -i sẽ xoá các document còn lại khỏi file. Luôn viết dạng (select(...) | .path) = value. yq -i giữ comment nhưng có thể đổi khoảng trắng/định dạng flow map, xem git diff trước khi commit.