2 giờ sáng. Telegram báo alert: service health check fail liên tục. SSH vào server, tail -f log ra một đống JSON dài vô tận trên một dòng duy nhất. Cần biết ngay field status đang là gì và node nào trong cluster đang bị lỗi.
Lúc đó có 3 lựa chọn: grep để tìm text thô, mở Python để parse JSON, hoặc dùng jq. Đó là lần đầu mình hiểu thực sự tại sao jq được sinh ra.
So sánh 3 cách xử lý JSON trong Terminal
Cùng bài toán: API trả về response dạng JSON và cần extract field status:
curl -s https://api.example.com/health
# Output: {"id":1,"status":"error","message":"Connection timeout","node":"web-03"}
Cách 1: grep và sed
curl -s https://api.example.com/health | grep -o '"status":"[^"]*"'
# "status":"error"
Ưu điểm: Có sẵn trên mọi Linux, không cần cài gì thêm.
Nhược điểm: Kết quả vẫn là "status":"error", chưa phải giá trị thuần. Nếu server trả về "status" : "error" có thêm space, hoặc đổi thứ tự field, regex bắt sai hoặc không bắt được gì. Trên production lúc 2 giờ sáng, “tùy hên” không phải option tốt.
Cách 2: Python one-liner
curl -s https://api.example.com/health | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['status'])"
# error
Ưu điểm: Parse JSON đúng cách, không bị lừa bởi format hay thứ tự field.
Nhược điểm: Lệnh dài và khó gõ lúc não chưa thức dậy hoàn toàn. Khi cần truy cập nested object hay array, câu lệnh còn phức tạp hơn nhiều.
Cách 3: jq
curl -s https://api.example.com/health | jq '.status'
# "error"
Một lệnh. Ngắn. Rõ ràng. Kết quả ra ngay.
Phân tích: Khi nào dùng cách nào
- grep/sed: Chỉ khi server không cho phép cài thêm tool và JSON structure cực đơn giản, không bao giờ thay đổi format.
- Python: Khi cần logic phức tạp, xử lý điều kiện nhiều bước, hoặc transform dữ liệu rồi ghi ra file — những thứ jq làm được nhưng Python dễ maintain hơn trong script dài.
- jq: Mọi lúc cần filter, extract, transform JSON nhanh trong terminal hay shell script ngắn. Đây là lựa chọn mặc định.
Sau 3 năm quản lý hơn 10 VPS, mình đã gặp cảnh này một lần: API vendor thay format response, grep âm thầm không bắt được gì, script vẫn chạy như bình thường — chỉ là status mình đọc được là một chuỗi empty. jq không có vấn đề đó. Nó parse đúng chuẩn, không phụ thuộc vào format hay thứ tự field.
Cài đặt jq
# Ubuntu/Debian
sudo apt install jq
# CentOS/AlmaLinux/RHEL
sudo dnf install jq
# Arch Linux
sudo pacman -S jq
# Kiểm tra
jq --version
# jq-1.7.1
Cú pháp cơ bản jq
Format JSON cho dễ đọc
Bước đầu tiên khi debug: dump toàn bộ JSON ra với format đẹp:
curl -s https://api.example.com/health | jq '.'
Dấu chấm . nghĩa là “lấy toàn bộ input và format lại”. Thay vì một dòng dài không đọc được, bạn thấy:
{
"id": 1,
"status": "error",
"message": "Connection timeout",
"node": "web-03"
}
Lấy field cụ thể
# Lấy một field
echo '{"status":"error","node":"web-03"}' | jq '.status'
# "error"
# Lấy nhiều field cùng lúc
jq '.status, .node'
# Nested field
jq '.server.config.port'
Làm việc với array
cat nodes.json
# [{"name":"web-01","status":"ok"},{"name":"web-02","status":"ok"},{"name":"web-03","status":"error"}]
# Tất cả elements
cat nodes.json | jq '.[]'
# Element đầu tiên (index 0)
cat nodes.json | jq '.[0]'
# Lấy field name của từng element
cat nodes.json | jq '.[].name'
# "web-01"
# "web-02"
# "web-03"
Filter với select() — thứ dùng nhiều nhất khi debug
Lọc ra chính xác node đang lỗi thay vì đọc toàn bộ list:
cat nodes.json | jq '.[] | select(.status == "error")'
# {
# "name": "web-03",
# "status": "error"
# }
# Chỉ lấy tên node đang lỗi
cat nodes.json | jq -r '.[] | select(.status == "error") | .name'
# web-03
Ứng dụng thực tế với Docker và Kubernetes
jq không chỉ dùng với API bên ngoài. Docker và Kubernetes đều output JSON — và đây là lúc jq thực sự phát huy hết khả năng:
# Xem tên và IP của tất cả containers trong bridge network
docker network inspect bridge | jq '.[0].Containers | to_entries[] | {name: .value.Name, ip: .value.IPv4Address}'
# Xem port mapping của container nginx
docker inspect nginx | jq '.[0].NetworkSettings.Ports'
# Lấy biến môi trường database từ container app
docker inspect myapp | jq -r '.[0].Config.Env[]' | grep DB_
# Tìm pod Kubernetes không ở trạng thái Running
kubectl get pods -o json | jq -r '.items[] | select(.status.phase != "Running") | .metadata.name'
Transform dữ liệu — tạo object mới từ response
# Tạo report gọn từ danh sách node
curl -s https://api.example.com/nodes | jq '[.[] | {node: .name, healthy: (.status == "ok")}]'
# [
# {"node": "web-01", "healthy": true},
# {"node": "web-03", "healthy": false}
# ]
# Đếm số node đang lỗi
cat nodes.json | jq '[.[] | select(.status == "error")] | length'
# 1
Dùng kết quả jq trong biến shell
# Mặc định jq bọc string trong dấu ngoặc kép
echo '{"node":"web-03"}' | jq '.node'
# "web-03"
# Flag -r bỏ ngoặc kép — dùng trực tiếp trong biến
NODE=$(curl -s https://api.example.com/health | jq -r '.node')
ssh admin@$NODE 'sudo systemctl restart myapp'
Xem JSON khi không ở trên server
Đôi khi cần xem cấu trúc JSON response trước khi viết jq filter — nhưng đang ngồi máy local, chưa SSH vào server. Lúc đó mình hay dùng JSON Formatter của ToolCraft: paste JSON vào, format ngay, syntax highlighting rõ ràng và báo lỗi cú pháp tức thì. Tool chạy hoàn toàn trên trình duyệt, không gửi data đi đâu — quan trọng khi API response chứa token hay thông tin nhạy cảm.
Nếu làm nhiều với Kubernetes hay Ansible, YAML ↔ JSON Converter trên cùng site cũng rất tiện — convert manifest YAML sang JSON để viết và test jq filter, rồi convert ngược lại khi cần.
Cheat sheet jq thường dùng
jq '.' # Format đẹp
jq '.field' # Lấy field
jq '.a.b.c' # Nested field
jq '.[]' # Tất cả array elements
jq '.[0]' # Element đầu (index 0)
jq '.[] | select(.x == "val")' # Filter by string value
jq '.[] | select(.n > 10)' # Filter by number
jq '{new_key: .old_key}' # Tạo object mới
jq '[.[] | .name]' # Tạo array từ field
jq 'length' # Đếm elements
jq 'keys' # List keys của object
jq 'unique' # Unique values
jq 'sort_by(.field)' # Sort by field
jq -r '.field' # Raw output (bỏ dấu ngoặc kép)
jq -c '.' # Compact output (1 dòng)
Từ lần debug lúc 2 giờ sáng đó đến nay, jq luôn là thứ đầu tiên mình cài khi setup server mới. Thêm sudo apt install jq vào runbook setup là xong — lần sau gặp đống JSON trong log sẽ không còn phải copy vào trình duyệt mới đọc được nữa.

