jq 사용법 총정리 — JSON 파싱부터 변환까지 실전 가이드
JSON은 현대 소프트웨어의 공용어입니다. REST API 응답, Docker·Kubernetes 설정, CI/CD 파이프라인 출력, package.json까지 — 개발자가 매일 마주치는 데이터의 상당 부분이 JSON 형태입니다. API 하나를 호출하면 수백 줄의 JSON이 쏟아지고, 로그 파일을 열면 한 줄 한 줄이 JSON 객체인 JSONL 포맷입니다. 이 모든 상황에서 커맨드라인 JSON 프로세서 jq는 복잡한 데이터를 즉시 파싱하고 변환할 수 있는 가장 실용적인 도구입니다.
문제는 이 JSON을 다루는 방식이 의외로 비효율적이라는 점입니다. grep으로 키워드를 찾거나, Python 스크립트를 별도로 작성하거나, 눈으로 직접 중괄호를 세어가며 값을 찾곤 합니다. 구조화된 데이터를 비구조적인 도구로 처리하는 셈이죠. grep은 JSON의 중첩 구조를 이해하지 못하고, sed나 awk는 키-값 관계를 파악하지 못합니다.
jq는 이 문제를 정면으로 해결하는 명령줄 JSON 프로세서입니다. SQL이 관계형 데이터베이스에 하는 일을, jq가 JSON에 합니다. 한 줄의 필터 표현식으로 깊이 중첩된 JSON 구조에서 원하는 값을 추출하고, 조건에 따라 걸러내고, 완전히 새로운 형태로 재구성할 수 있습니다. 2012년에 처음 공개된 이후 꾸준히 발전해, 2026년 현재 대부분의 리눅스 배포판과 macOS에 기본 또는 한 줄 설치로 제공됩니다.
이 글에서는 jq의 설치부터 기본 문법, 실무에서 바로 복사해 쓸 수 있는 레시피, 고급 기법, 그리고 대안 도구 비교까지 하나의 가이드로 정리합니다. 터미널에서 JSON을 다루는 모든 상황에 이 글 하나면 충분합니다.

jq 설치 — 모든 운영체제에서 1분 안에 준비
jq는 대부분의 운영체제에서 패키지 매니저 한 줄로 설치할 수 있습니다. 별도의 런타임이나 의존성이 필요 없는 단일 바이너리이므로, 설치 후 바로 사용 가능합니다.
Windows
# winget (권장)
winget install jqlang.jq
# scoop
scoop install jq
# chocolatey
choco install jq
macOS
brew install jq
Linux
# Debian / Ubuntu
sudo apt install jq
# Fedora / RHEL
sudo dnf install jq
# Arch Linux
sudo pacman -S jq
설치 확인
jq --version
# jq-1.7.1
버전 번호가 출력되면 준비 완료입니다. 이 글의 모든 예제는 jq 1.7 이상을 기준으로 작성했지만, 기본 문법은 1.5 이상이면 대부분 동일하게 동작합니다.
이 글에서 사용하는 예제 데이터
앞으로 대부분의 예제에서 아래 JSON 파일을 사용합니다. users.json이라는 이름으로 저장해두면 따라 하기 편합니다.
{
"team": "backend",
"users": [
{"name": "김철수", "age": 28, "role": "developer", "active": true, "lang": ["Python", "Go"]},
{"name": "이영희", "age": 35, "role": "designer", "active": true, "lang": ["Figma"]},
{"name": "박민수", "age": 42, "role": "developer", "active": false, "lang": ["Java", "Kotlin"]},
{"name": "정수진", "age": 31, "role": "manager", "active": true, "lang": []}
]
}
4명의 팀원 정보가 담긴 간단한 구조지만, jq의 거의 모든 기능을 시연하기에 충분합니다.
jq 기본 문법 — 필드 접근과 출력
jq의 가장 기본적인 동작은 JSON을 입력받아 필터를 적용하고 결과를 출력하는 것입니다. 모든 jq 명령은 입력 | jq '필터' 형태를 따릅니다.
포맷팅 출력 (.)
가장 단순한 필터는 점(.) 하나입니다. 입력을 그대로 통과시키되, 들여쓰기와 색상을 적용해 읽기 쉽게 출력합니다.
echo '{"name":"김철수","age":28}' | jq '.'
# 출력:
# {
# "name": "김철수",
# "age": 28
# }
API 응답을 눈으로 확인할 때, curl ... | jq '.' 한 줄이면 복잡한 JSON도 깔끔하게 정리됩니다. 이것만으로도 jq를 설치할 가치가 있습니다.
필드 접근 (.key)
점 뒤에 키 이름을 붙이면 해당 필드의 값을 추출합니다.
# 단일 필드
cat users.json | jq '.team'
# "backend"
# 여러 필드를 콤마로 구분
echo '{"name": "김철수", "age": 28}' | jq '.name, .age'
# "김철수"
# 28
중첩 필드 접근 (.a.b.c)
점을 연결하면 중첩된 객체 안의 값에 도달할 수 있습니다.
echo '{"user": {"profile": {"city": "서울"}}}' | jq '.user.profile.city'
# "서울"
raw 출력 (-r 옵션)
기본적으로 jq는 문자열을 따옴표로 감싸서 출력합니다. 셸 스크립트에서 변수로 받거나 다른 명령에 파이프할 때는 따옴표가 방해되므로, -r(raw output) 옵션을 씁니다.
# 기본 출력 — 따옴표 포함
cat users.json | jq '.team'
# "backend"
# raw 출력 — 따옴표 제거
cat users.json | jq -r '.team'
# backend
-r 옵션은 jq를 셸 파이프라인에 통합할 때 거의 항상 사용하므로, 손에 익혀두면 좋습니다.
옵셔널 접근 (.key?)
존재하지 않는 키에 접근하면 jq는 null을 반환합니다. 배열이 아닌 값에 배열 연산을 시도하는 등 타입 불일치가 발생하면 에러가 나는데, 물음표(?)를 붙이면 에러 대신 조용히 넘어갑니다.
# null 반환 (에러 아님)
echo '{"name": "김철수"}' | jq '.age'
# null
# 타입 불일치 — ?로 에러 억제
echo '{"name": "김철수"}' | jq '.name[]?'
# (출력 없음, 에러 없음)

배열 다루기 — 인덱싱, 슬라이싱, 순회
JSON 데이터에서 배열은 가장 자주 등장하는 구조입니다. jq는 배열을 다루는 강력한 도구를 제공합니다.
인덱스 접근
# 첫 번째 요소
cat users.json | jq '.users[0].name'
# "김철수"
# 마지막 요소 (음수 인덱스)
cat users.json | jq '.users[-1].name'
# "정수진"
# 슬라이싱 (인덱스 1부터 2까지, 3 미포함)
cat users.json | jq '.users[1:3] | .[].name'
# "이영희"
# "박민수"
배열 순회 (.[])
.[]는 배열의 모든 요소를 하나씩 꺼내는 연산입니다. jq에서 가장 자주 쓰이는 패턴 중 하나입니다.
# 모든 사용자의 이름 출력
cat users.json | jq '.users[].name'
# "김철수"
# "이영희"
# "박민수"
# "정수진"
주의할 점은 .[]가 여러 개의 독립된 출력을 만든다는 것입니다. 하나의 배열로 다시 묶고 싶으면 전체를 대괄호로 감쌉니다.
# 배열로 수집
cat users.json | jq '[.users[].name]'
# ["김철수", "이영희", "박민수", "정수진"]
배열 길이와 존재 확인
# 배열 길이
cat users.json | jq '.users | length'
# 4
# 빈 배열 확인
cat users.json | jq '.users[] | select(.lang | length == 0) | .name'
# "정수진"
파이프라인과 필터 — jq의 핵심 동력
유닉스 셸에서 |로 명령을 연결하듯, jq에서도 |로 필터를 연결합니다. 앞 필터의 출력이 뒤 필터의 입력이 됩니다. 이 파이프라인이 jq의 진짜 힘입니다.
select() — 조건 필터링
select(조건)은 조건이 참인 요소만 통과시킵니다. SQL의 WHERE에 해당합니다.
# 개발자만 추출
cat users.json | jq '.users[] | select(.role == "developer")'
# 30세 이상이면서 활성 상태인 사용자의 이름
cat users.json | jq '.users[] | select(.age >= 30 and .active) | .name'
# "이영희"
# "정수진"
# 특정 언어를 사용하는 사용자
cat users.json | jq '.users[] | select(.lang | index("Python")) | .name'
# "김철수"
map() — 배열 변환
map(필터)는 배열의 각 요소에 필터를 적용하고 결과를 새 배열로 반환합니다. [.[] | 필터]의 축약형입니다.
# 모든 사용자 이름을 배열로
cat users.json | jq '.users | map(.name)'
# ["김철수", "이영희", "박민수", "정수진"]
# 30세 이상만 필터링 후 이름 추출
cat users.json | jq '.users | map(select(.age >= 30)) | map(.name)'
# ["이영희", "박민수", "정수진"]
sort_by()와 reverse
# 나이 오름차순 정렬 후 이름 추출
cat users.json | jq '.users | sort_by(.age) | map(.name)'
# ["김철수", "정수진", "이영희", "박민수"]
# 내림차순
cat users.json | jq '.users | sort_by(.age) | reverse | map(.name)'
# ["박민수", "이영희", "정수진", "김철수"]
group_by()와 unique_by()
# 역할별 그룹핑
cat users.json | jq '.users | group_by(.role) | map({role: .[0].role, count: length})'
# [{"role":"designer","count":1},{"role":"developer","count":2},{"role":"manager","count":1}]
# 역할 목록 (중복 제거)
cat users.json | jq '.users | unique_by(.role) | map(.role)'
# ["designer", "developer", "manager"]
객체 구성과 변환 — 원하는 형태로 재구성
jq의 진짜 강점은 입력 JSON을 완전히 다른 구조로 변환할 수 있다는 점입니다. 중괄호와 대괄호를 사용해 새로운 객체와 배열을 자유롭게 만들 수 있습니다.
새 객체 만들기
# 필요한 필드만 골라 새 객체 구성
cat users.json | jq '.users[] | {이름: .name, 역할: .role}'
# {"이름":"김철수","역할":"developer"}
# {"이름":"이영희","역할":"designer"}
# ...
# 배열로 수집
cat users.json | jq '[.users[] | {이름: .name, 역할: .role}]'
값 수정 (|= 업데이트 연산자)
|=는 기존 값을 필터로 변환하여 제자리에서 업데이트합니다.
# 첫 번째 사용자의 나이를 1 증가
cat users.json | jq '.users[0].age |= . + 1'
# 모든 사용자의 이름에 "님" 접미사 추가
cat users.json | jq '.users[].name |= . + "님"'
필드 추가와 삭제
# 모든 사용자에 team 필드 추가
cat users.json | jq '.users[] | . + {"team": "backend"}'
# active 필드 삭제
cat users.json | jq '.users | map(del(.active))'
# 여러 필드 한꺼번에 삭제
cat users.json | jq '.users | map(del(.active, .lang))'
두 객체 병합
# * 연산자로 깊은 병합
echo '{"a":1,"b":{"x":10}}' | jq '. * {"b":{"y":20},"c":3}'
# {"a":1,"b":{"x":10,"y":20},"c":3}
핵심 내장 함수 총정리
jq에는 수십 개의 내장 함수가 있습니다. 그 중 실무에서 가장 자주 쓰이는 함수들을 정리합니다.
타입과 구조 검사
# type — 값의 타입 확인
echo '42' | jq 'type' # "number"
echo '"hello"' | jq 'type' # "string"
echo 'true' | jq 'type' # "boolean"
echo 'null' | jq 'type' # "null"
echo '[1,2]' | jq 'type' # "array"
echo '{"a":1}' | jq 'type' # "object"
# length — 길이 (배열: 요소 수, 문자열: 글자 수, 객체: 키 수)
echo '[1,2,3]' | jq 'length' # 3
echo '"안녕하세요"' | jq 'length' # 5
echo '{"a":1,"b":2}' | jq 'length' # 2
# keys, values — 객체의 키와 값 배열
echo '{"name":"김","age":28}' | jq 'keys' # ["age","name"]
echo '{"name":"김","age":28}' | jq 'values' # ["김",28]
# has() — 키 존재 여부
echo '{"name":"김"}' | jq 'has("name")' # true
echo '{"name":"김"}' | jq 'has("email")' # false
숫자·배열 집계
# add — 배열의 합산 (숫자는 덧셈, 문자열은 연결)
echo '[1,2,3,4,5]' | jq 'add' # 15
echo '["a","b","c"]' | jq 'add' # "abc"
# min, max
echo '[3,1,4,1,5,9]' | jq 'min' # 1
echo '[3,1,4,1,5,9]' | jq 'max' # 9
# min_by, max_by
cat users.json | jq '.users | min_by(.age) | .name' # "김철수"
cat users.json | jq '.users | max_by(.age) | .name' # "박민수"
# flatten — 중첩 배열 평탄화
echo '[[1,2],[3,[4,5]]]' | jq 'flatten' # [1,2,3,4,5]
문자열 함수
# split, join
echo '"a,b,c,d"' | jq 'split(",")' # ["a","b","c","d"]
echo '["a","b","c"]' | jq 'join("-")' # "a-b-c"
# ascii_downcase, ascii_upcase
echo '"Hello World"' | jq 'ascii_downcase' # "hello world"
# ltrimstr, rtrimstr — 접두사/접미사 제거
echo '"hello.json"' | jq 'rtrimstr(".json")' # "hello"
# tostring, tonumber — 타입 변환
echo '42' | jq 'tostring' # "42"
echo '"42"' | jq 'tonumber' # 42
출력 포맷 (@format)
# @csv — CSV 형식 출력
cat users.json | jq -r '.users[] | [.name, .age, .role] | @csv'
# "김철수",28,"developer"
# "이영희",35,"designer"
# ...
# @tsv — 탭 구분 출력
cat users.json | jq -r '.users[] | [.name, .age, .role] | @tsv'
# @base64 / @base64d — Base64 인코딩/디코딩
echo '"hello world"' | jq '@base64' # "aGVsbG8gd29ybGQ="
echo '"aGVsbG8gd29ybGQ="' | jq '@base64d' # "hello world"
# @uri — URI 인코딩
echo '"검색어 테스트"' | jq '@uri'
실전 레시피 — 복사해서 바로 쓰는 패턴 7가지
이론은 충분합니다. 실무에서 자주 마주치는 구체적인 시나리오별로 바로 복사해서 사용할 수 있는 jq 패턴을 정리합니다.
레시피 1: cURL + jq로 API 응답 파싱
API를 호출하고 필요한 데이터만 추출하는 가장 흔한 패턴입니다.
# GitHub 리포지토리의 최신 릴리즈 정보
curl -s https://api.github.com/repos/jqlang/jq/releases/latest | jq '{
version: .tag_name,
published: .published_at,
assets: [.assets[] | {name: .name, size_mb: (.size / 1048576 | round)}]
}'
# 응답에서 특정 헤더 값과 함께 처리
curl -s https://httpbin.org/get | jq '{origin: .origin, headers: .headers | keys}'
레시피 2: Docker 컨테이너 정보 추출
# 실행 중인 컨테이너의 이름과 이미지만 추출
docker ps --format json | jq -s '[.[] | {name: .Names, image: .Image, status: .Status}]'
# 특정 컨테이너의 IP 주소 확인
docker inspect nginx | jq '.[0].NetworkSettings.Networks | to_entries[] | {network: .key, ip: .value.IPAddress}'
# 모든 컨테이너의 포트 매핑
docker inspect $(docker ps -q) | jq '.[] | {name: .Name, ports: .NetworkSettings.Ports}'
레시피 3: package.json 분석
# 의존성 목록과 총 개수
cat package.json | jq '{
name: .name,
version: .version,
deps: (.dependencies // {} | keys),
devDeps: (.devDependencies // {} | keys),
total: ((.dependencies // {} | length) + (.devDependencies // {} | length))
}'
# 특정 패키지가 의존성에 있는지 확인
cat package.json | jq '.dependencies | has("express")'
레시피 4: JSONL 로그 분석
한 줄에 하나의 JSON 객체가 들어있는 JSONL 형식은 구조화 로깅에서 표준처럼 사용됩니다. jq의 -s(slurp) 옵션이 빛나는 순간입니다.
# 에러 로그만 필터링
cat app.log | jq 'select(.level == "error")'
# 레벨별 로그 수 집계
cat app.log | jq -s 'group_by(.level) | map({level: .[0].level, count: length}) | sort_by(.count) | reverse'
# 최근 1시간 내 에러 로그의 메시지만 추출 (ISO 8601 날짜 비교)
cat app.log | jq 'select(.level == "error" and .timestamp > "2026-06-29T12:00:00")'
레시피 5: 환경변수를 활용한 동적 필터
--arg로 외부 값을 jq 변수로 주입하면, 셸 스크립트에서 유연하게 활용할 수 있습니다.
# 역할을 변수로 받아 필터링
jq --arg role "developer" '.users[] | select(.role == $role) | .name' users.json
# JSON 값을 변수로 전달 (--argjson은 따옴표 없이 JSON 파싱)
jq --argjson min_age 30 '.users[] | select(.age >= $min_age) | .name' users.json
# 셸 변수와 조합
TARGET_ROLE="designer"
jq --arg r "$TARGET_ROLE" '[.users[] | select(.role == $r)]' users.json
레시피 6: 여러 JSON 파일 병합
# 두 파일을 슬러프하여 하나의 배열로
jq -s '.' file1.json file2.json
# 두 배열 합치기
jq -s '.[0].users + .[1].users' team_a.json team_b.json
# --slurpfile로 참조 데이터 합류
jq --slurpfile roles roles.json '.users[] | . + {role_desc: ($roles[0][.role])}' users.json
레시피 7: JSON을 CSV로 변환하여 스프레드시트에 붙이기
# 헤더 포함 CSV 출력
cat users.json | jq -r '("name,age,role,active"), (.users[] | [.name, .age, .role, .active] | @csv)'
# 출력:
# name,age,role,active
# "김철수",28,"developer",true
# "이영희",35,"designer",true
# ...
고급 기법 — jq 마스터로 가는 길
기본 문법만으로도 대부분의 작업을 처리할 수 있지만, 복잡한 데이터 변환이 필요한 순간이 옵니다. 고급 기법을 알아두면 Python 스크립트 없이도 터미널에서 대부분을 해결할 수 있습니다.
조건문 (if-then-else)
# 나이 구간에 따라 카테고리 부여
cat users.json | jq '.users[] | {
name: .name,
level: (if .age < 30 then "주니어"
elif .age < 40 then "시니어"
else "리드" end)
}'
# {"name":"김철수","level":"주니어"}
# {"name":"이영희","level":"시니어"}
# {"name":"박민수","level":"리드"}
# {"name":"정수진","level":"시니어"}
대체 연산자 (//)
//는 왼쪽이 null이나 false일 때 오른쪽 값을 사용합니다. 다른 언어의 ??나 ||과 비슷합니다.
# email이 없으면 기본값 사용
echo '{"name": "김철수"}' | jq '.email // "미등록"'
# "미등록"
# 빈 배열일 때 기본값
echo '{"tags": []}' | jq '.tags | if length == 0 then ["untagged"] else . end'
try-catch 에러 처리
# 안전한 타입 변환
echo '["42", "hello", "7"]' | jq '[.[] | try tonumber]'
# [42, 7] ("hello"는 조용히 건너뜀)
# catch로 대체값 지정
echo '["42", "hello", "7"]' | jq '[.[] | (try tonumber catch -1)]'
# [42, -1, 7]
정규표현식
# test() — 매칭 여부 (boolean)
echo '["[email protected]", "invalid", "[email protected]"]' | jq '[.[] | select(test("@.*\\.\\w+$"))]'
# match() — 매칭 결과 상세
echo '"2026-06-29"' | jq 'match("(?[0-9]{4})-(?[0-9]{2})-(?[0-9]{2})") | .captures | map({(.name): .string}) | add'
# {"y":"2026","m":"06","d":"29"}
# gsub() — 치환
echo '"Hello World 2026"' | jq 'gsub("[0-9]+"; "XXXX")'
# "Hello World XXXX"
reduce — 누적 연산
reduce는 배열의 모든 요소를 하나의 값으로 접는 연산입니다. 복잡한 집계에 필수입니다.
# 합계 계산
echo '[1,2,3,4,5]' | jq 'reduce .[] as $x (0; . + $x)'
# 15
# 역할별 인원수를 객체로 집계
cat users.json | jq 'reduce .users[] as $u ({}; .[$u.role] = ((.[$u.role] // 0) + 1))'
# {"developer":2,"designer":1,"manager":1}
문자열 보간
큰따옴표 안에서 \(표현식)을 쓰면 값을 문자열에 삽입할 수 있습니다. 보고서나 메시지를 만들 때 유용합니다.
cat users.json | jq -r '.users[] | "\(.name)님(\(.age)세) — \(.role)"'
# 김철수님(28세) — developer
# 이영희님(35세) — designer
# 박민수님(42세) — developer
# 정수진님(31세) — manager
사용자 정의 함수 (def)
# 평균을 구하는 함수 정의
echo '[10, 20, 30, 40, 50]' | jq 'def avg: add / length; avg'
# 30
# 여러 함수 조합
cat users.json | jq '
def active_users: [.[] | select(.active)];
def names: [.[] | .name];
.users | active_users | names
'
# ["김철수","이영희","정수진"]
jq 생산성을 높이는 팁
jq를 일상 도구로 활용하기 위한 실용적인 팁을 모았습니다.
jqplay.org — 온라인 실습 환경
jqplay.org는 브라우저에서 jq 필터를 실시간으로 테스트할 수 있는 온라인 도구입니다. 입력 JSON과 필터를 입력하면 결과를 즉시 확인할 수 있어, 복잡한 필터를 구성할 때 먼저 이 사이트에서 실험한 뒤 셸에 적용하면 편합니다.
셸 별칭 설정
자주 쓰는 패턴은 셸 별칭이나 함수로 등록하면 생산성이 올라갑니다.
# .bashrc 또는 .zshrc에 추가
alias jqp='jq .'
alias jqc='jq -c .'
alias jqk='jq keys'
# PowerShell $PROFILE에 추가
function jqp { $input | jq '.' }
function jqc { $input | jq -c '.' }
compact 출력 (-c)
-c 옵션은 결과를 한 줄로 압축 출력합니다. 파이프라인에서 다음 명령으로 전달하거나, JSONL 형식으로 저장할 때 사용합니다.
# 각 사용자를 한 줄 JSON으로 출력
cat users.json | jq -c '.users[]'
# {"name":"김철수","age":28,"role":"developer",...}
# {"name":"이영희","age":35,"role":"designer",...}
cURL과의 궁합
cURL의 -s(silent) 옵션과 jq는 최고의 조합입니다. 진행 바와 에러 메시지를 숨기고, 깔끔한 JSON만 jq로 넘깁니다.
# 기본 패턴
curl -s URL | jq '필터'
# POST 요청 후 응답 파싱
curl -s -X POST -H 'Content-Type: application/json' \
-d '{"query": "test"}' \
http://localhost:8080/api | jq '.results[] | .title'
null 입력으로 JSON 생성 (-n)
-n 옵션은 입력 없이 jq를 실행합니다. JSON을 처음부터 만들 때 유용합니다.
# 셸 변수로부터 JSON 생성
jq -n --arg name "김철수" --argjson age 28 '{name: $name, age: $age}'
# {"name":"김철수","age":28}

jq 대안 도구 비교
jq가 사실상 표준이지만, 특정 상황에서 더 나은 선택지가 있습니다. 주요 대안 도구를 비교합니다.
gojq — Go 구현, YAML 지원
gojq는 jq를 Go 언어로 재구현한 도구입니다. jq와 거의 100% 호환되면서, YAML 입출력을 기본 지원합니다. Kubernetes 설정 파일(YAML)과 API 응답(JSON)을 하나의 도구로 처리할 수 있어, DevOps 엔지니어에게 특히 유용합니다.
# YAML 입력 처리
gojq --yaml-input '.metadata.name' deployment.yaml
# YAML 출력
echo '{"a":1,"b":2}' | gojq --yaml-output .
jaq — Rust 구현, 뛰어난 성능
jaq는 Rust로 작성된 jq 대안으로, 대용량 JSON 처리에서 jq보다 2~5배 빠른 성능을 보여줍니다. 문법은 jq와 대부분 호환되지만, 일부 고급 기능(SQL 스타일 연산자 등)에서 차이가 있습니다. 수 GB 크기의 JSON 파일을 다루거나, 파이프라인에서 병목이 jq 처리 속도인 경우에 고려할 만합니다.
# 설치
cargo install jaq
# 또는 brew install jaq
# 사용법은 jq와 동일
cat large_file.json | jaq '.items | length'
fx — 인터랙티브 JSON 탐색
fx는 터미널에서 JSON을 인터랙티브하게 탐색하는 도구입니다. 트리 구조로 JSON을 시각화하고, 키보드로 펼치고 접으며 탐색할 수 있습니다. 구조를 모르는 거대한 JSON을 처음 살펴볼 때 jq보다 편리합니다. 필터를 확정한 뒤 jq 명령으로 옮기는 워크플로가 효율적입니다.
# 설치
npm install -g fx
# 또는 brew install fx
# 인터랙티브 모드
curl -s https://api.github.com/repos/jqlang/jq | fx
yq — YAML·XML·TOML용 jq
yq는 jq 문법을 YAML, XML, TOML, CSV에 확장한 도구입니다. jq를 이미 알고 있다면 추가 학습 비용 없이 YAML 파일을 조작할 수 있습니다. Docker Compose, GitHub Actions 워크플로, Helm 차트 등 YAML 파일을 많이 다루는 환경에서 필수입니다.
# 설치
brew install yq # mikefarah 버전
pip install yq # kislyuk 버전 (jq wrapper)
# YAML에서 값 추출 (mikefarah/yq)
yq '.services.web.image' docker-compose.yml
# YAML 값 수정 (제자리)
yq -i '.services.web.ports[0] = "8080:80"' docker-compose.yml
선택 기준 요약
- JSON만 다룬다면 → jq가 표준이자 최선. 문서와 커뮤니티가 가장 풍부합니다.
- YAML도 함께 다룬다면 → gojq 또는 yq. Kubernetes·Docker 환경에서 유리합니다.
- 대용량 파일 처리가 핵심이면 → jaq. Rust의 성능 이점이 GB급 파일에서 체감됩니다.
- 구조 탐색이 먼저면 → fx. 시각적으로 구조를 파악한 뒤 jq 필터를 작성하는 흐름이 효율적입니다.
마무리 — jq는 개발자의 기본기
jq는 단순한 유틸리티가 아니라, 현대 개발 워크플로의 필수 도구입니다. API 디버깅, 로그 분석, CI/CD 파이프라인 스크립팅, 설정 파일 관리 — JSON이 등장하는 거의 모든 순간에 jq 한 줄이 Python 스크립트 20줄을 대체합니다.
이 글에서 다룬 내용을 한번에 외울 필요는 없습니다. 기본 패턴(.field, .[], select(), map())만 기억하고, 나머지는 필요할 때 이 가이드를 참고하면 됩니다. 처음에는 curl ... | jq '.'로 API 응답을 포맷팅하는 것부터 시작해보세요. 한번 손에 익으면, jq 없이 JSON을 다루던 시절로 돌아갈 수 없게 될 것입니다.
jq 공식 매뉴얼(jqlang.github.io/jq/manual)에는 이 글에서 다루지 못한 수십 개의 내장 함수가 더 문서화되어 있으니, 심화 학습에 활용해보시기 바랍니다.
참고 자료
- jq Manual — jq 공식 매뉴얼로, 모든 내장 함수와 문법을 상세히 설명합니다.
- jq (programming language) - Wikipedia — jq의 역사, 설계 철학, 주요 기능을 정리한 위키백과 문서입니다.