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.