jq — JSON 쿼리 및 변환
선택적 읽기 규칙
다음으로 시작:
references/senior-master-standard.mdreferences/usage-routing.mdreferences/quality-checklist.md
그런 다음 사용자의 실제 작업과 일치하는 상속된 문서, 스크립트, 자산 또는 예제만 로드합니다.
개요
jq는 JSON을 쿼리하고 재구성하는 표준 CLI 도구입니다. 이 스킬은 실용적이고 전문가 수준의 사용법을 다룹니다: 깊이 중첩된 데이터 필터링, 구조 변환, 값 집계, 셸 파이프라인에 jq 구성하기. 모든 예제는 실제 워크플로에 복사하여 붙여넣기 할 수 있습니다.
이 스킬을 사용해야 하는 경우
- 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}]'
집계 및 축소
# 모든 값 합계
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'
실용적인 셸 통합
# 파일에서 읽기
jq '.users' data.json
# 추가 파이프라인을 위한 압축 출력 (공백 없음)
jq -c '.[]' records.json | while IFS= read -r record; do
echo "처리 중: $record"
done
# 셸 변수를 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
# 명령의 null-safe 파이프라인
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결과를 셸 변수나 다른 명령에 전달할 때 항상-r(원시 출력)을 사용하여 JSON 문자열 따옴표를 제거하세요- 셸 변수를 안전하게 주입하려면
--arg/--argjson을 사용하세요 — 필터 문자열에 직접 셸 변수를 보간하지 마세요 - 가독성을 위해
[.[] | f]보다map(f)를 선호하세요 - 개행으로 구분된 JSON 파이프라인에는
-c(압축)를 사용하고, 사람이 읽을 수 있는 디버깅을 위해서는 생략하세요 - 스크립트에 포함하기 전에
jq -n과 리터럴 입력으로 대화식으로 필터를 테스트하세요 - 원하지 않는 요소를
null로 필터링하는 대신empty를 사용하여 제거하세요
보안 및 안전 참고 사항
jq는 설계상 읽기 전용입니다 — 파일을 쓰거나 명령을 실행할 수 없습니다- 신뢰할 수 없는 JSON 필드 값을 셸 명령에 직접 포함하지 마세요. 항상 인용하거나
--arg를 사용하세요
일반적인 함정
-
문제:
jq가 예상 값 대신null을 출력합니다 해결책: 키 이름의 오타를 확인하고;keys를 사용하여 실제 필드 이름을 검사하세요. JSON은 대소문자를 구분합니다. -
문제: 숫자가 출력에서 문자열로 인용됩니다 해결책: 숫자 값을 주입할 때
--arg대신--argjson을 사용하세요. -
문제: 필터가 터미널에서는 작동하지만 스크립트에서는 실패합니다 해결책: 필터 문자열이 셸에서 작은따옴표를 사용하여 변수 확장을 방지하는지 확인하세요. 예:
jq '.field'(틀림:jq ".field"). -
문제: 빈 배열에서
add가null을 반환합니다 해결책:add // 0또는add // ""를 사용하여 기본값을 제공하세요. -
문제: 대용량 파일 스트리밍이 느립니다 해결책:
jq --stream을 사용하거나 매우 큰 파일의 경우jstream/gron으로 전환하세요.
관련 스킬
@bash-pro— 강력한 셸 스크립트에 jq 호출 래핑@bash-linux— 일반적인 셸 파이프라인 패턴@github-automation— GitHub CLI JSON 출력과 함께 jq 사용
제한 사항
- 작업이 위에서 설명한 범위와 명확하게 일치하는 경우에만 이 스킬을 사용하세요.
- 출력을 환경별 검증, 테스트 또는 전문가 검토를 대체하는 것으로 취급하지 마세요.
- 필요한 입력, 권한, 안전 경계 또는 성공 기준이 누락된 경우 중단하고 명확히 설명을 요청하세요.