왜 CLI 도구를 익혀야 하는가?
GUI 도구는 직관적이지만, CLI 도구는 자동화, 파이프라인 조합, 속도 면에서 압도적입니다. 요리에 비유하면, GUI는 전자레인지(편리하지만 제한적)이고 CLI는 칼과 도마(숙련되면 모든 요리가 가능)입니다.
이 글에서는 일상 개발에서 즉시 생산성을 높여주는 4가지 CLI 도구를 정리합니다.
jq: JSON 처리의 스위스 칼
jq는 커맨드라인에서 JSON을 파싱, 필터링, 변환하는 도구입니다. API 응답을 분석하거나, JSON 로그를 처리할 때 필수입니다.
설치
# macOS
brew install jq
# Ubuntu/Debian
sudo apt install jq
# Windows (scoop)
scoop install jq
기본 사용법
# JSON 이쁘게 출력 (Pretty Print)
echo '{"name":"김철수","age":30}' | jq '.'
# 출력:
# {
# "name": "김철수",
# "age": 30
# }
# 특정 필드 추출
echo '{"name":"김철수","age":30,"city":"서울"}' | jq '.name'
# 출력: "김철수"
# 따옴표 없이 출력 (-r 옵션)
echo '{"name":"김철수"}' | jq -r '.name'
# 출력: 김철수
# 배열에서 필터링
echo '[{"name":"김철수","age":30},{"name":"이영희","age":25}]' | jq '.[] | select(.age > 27)'
# 출력: {"name":"김철수","age":30}
# 새로운 구조로 변환
echo '[{"first":"철수","last":"김"},{"first":"영희","last":"이"}]' | \
jq '[.[] | {full_name: (.last + .first), initial: .last}]'
# 출력:
# [
# { "full_name": "김철수", "initial": "김" },
# { "full_name": "이영희", "initial": "이" }
# ]
실전 예제: API 응답 분석
# GitHub API에서 리포지토리 정보 추출
curl -s "https://api.github.com/users/torvalds/repos?per_page=5" | \
jq '[.[] | {name: .name, stars: .stargazers_count, language: .language}]' | \
jq 'sort_by(-.stars)'
# 출력:
# [
# { "name": "linux", "stars": 180000, "language": "C" },
# ...
# ]
# JSON 로그에서 에러만 추출
cat app.log | jq -r 'select(.level == "error") | "\(.timestamp) \(.message)"'
# 출력: 2026-04-07T10:00:01 Database connection failed
# 중첩 JSON에서 깊은 필드 접근
echo '{"data":{"users":[{"id":1,"profile":{"email":"a@b.com"}}]}}' | \
jq '.data.users[0].profile.email'
# 출력: "a@b.com"
HTTPie: curl의 현대적 대안
HTTPie는 사람이 읽기 쉬운 HTTP 클라이언트입니다. curl보다 직관적인 문법으로 API를 테스트할 수 있습니다.
설치
# macOS
brew install httpie
# pip (모든 플랫폼)
pip install httpie
# Ubuntu
sudo apt install httpie
기본 사용법
# GET 요청 (프로토콜, 메서드 생략 가능)
http httpbin.org/get
# 출력: (자동 색상 + 포매팅된 JSON 응답)
# POST 요청 + JSON 본문 (= 구분자로 키-값 전달)
http POST httpbin.org/post name=김철수 age:=30 active:=true
# name=값 → 문자열
# age:=30 → 숫자 (: 붙이면 JSON 타입)
# active:=true → 불린
# 헤더 추가 (: 구분자)
http GET api.example.com/users \
Authorization:"Bearer eyJhbGci..." \
Accept:application/json
# 파일 업로드
http --form POST api.example.com/upload file@./document.pdf
# 폼 데이터 전송
http --form POST api.example.com/login username=admin password=1234
curl과 비교
# curl로 POST 요청
curl -X POST https://api.example.com/users \
-H "Content-Type: application/json" \
-H "Authorization: Bearer token123" \
-d '{"name":"김철수","age":30}'
# HTTPie로 동일한 요청 (훨씬 간결)
http POST api.example.com/users \
name=김철수 age:=30 \
Authorization:"Bearer token123"
| 기능 | curl | HTTPie |
|---|---|---|
| JSON 포매팅 | 수동 (` | jq`) |
| 색상 출력 | 없음 | 자동 |
| JSON 본문 | -d '{"key":"val"}' | key=val |
| 헤더 추가 | -H "Key: Val" | Key:Val |
| 파일 업로드 | -F "file=@path" | file@path |
세션 기능
# 세션 저장 — 쿠키/헤더 유지
http --session=myapi POST api.example.com/login username=admin password=1234
# 로그인 쿠키가 세션에 저장됨
# 이후 요청에서 세션 재사용 (인증 정보 자동 포함)
http --session=myapi GET api.example.com/profile
# 쿠키가 자동으로 전송됨
fzf: 퍼지 파인더
fzf는 모든 목록을 실시간 퍼지 검색할 수 있는 도구입니다. 파일, 히스토리, 브랜치 등 무엇이든 빠르게 찾을 수 있습니다.
설치
# macOS
brew install fzf
$(brew --prefix)/opt/fzf/install # 키 바인딩 설정
# Ubuntu
sudo apt install fzf
# Git에서 직접 설치
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf
~/.fzf/install
기본 사용법
# 현재 디렉토리에서 파일 검색
fzf
# 입력: "comp"
# 매칭: src/components/Button.tsx, docker-compose.yml, ...
# ↑↓로 선택, Enter로 확정
# 파이프와 조합
cat package.json | jq -r '.dependencies | keys[]' | fzf
# npm 패키지 목록에서 퍼지 검색
# 미리보기 포함 파일 검색
fzf --preview 'cat {}'
# 선택한 파일의 내용을 오른쪽에 미리보기
# 여러 항목 선택 (Tab으로 선택, Enter로 확정)
fzf --multi
셸 통합 (핵심 기능)
# fzf 설치 시 자동 설정되는 키 바인딩
# Ctrl+R — 명령어 히스토리 퍼지 검색 (가장 많이 사용!)
# 평소: history | grep docker → 느림
# fzf: Ctrl+R → "docker" 입력 → 즉시 찾기
# Ctrl+T — 현재 디렉토리에서 파일/디렉토리 퍼지 검색
# vim Ctrl+T → 파일 선택 → vim으로 열기
# Alt+C — 디렉토리 퍼지 검색 후 cd
# Alt+C → "comp" → src/components/ 로 이동
Git과 조합
# Git 브랜치 퍼지 검색 후 체크아웃
git branch -a | fzf | xargs git checkout
# Git 로그에서 커밋 검색
git log --oneline | fzf --preview 'git show {1}'
# 커밋 해시 기준으로 diff 미리보기
# 변경된 파일 중 선택하여 add
git status -s | fzf --multi | awk '{print $2}' | xargs git add
# 셸 함수로 등록 (~/.bashrc 또는 ~/.zshrc)
# Git 브랜치 퍼지 체크아웃
gbf() {
local branch
branch=$(git branch -a | sed 's/^..//' | sed 's|remotes/origin/||' | sort -u | fzf)
if [ -n "$branch" ]; then
git checkout "$branch"
fi
}
ripgrep (rg): grep의 초고속 대안
ripgrep은 코드 검색에 최적화된 grep 대안입니다. .gitignore를 자동 인식하고, 기본적으로 재귀 검색하며, grep보다 2~5배 빠릅니다.
설치
# macOS
brew install ripgrep
# Ubuntu
sudo apt install ripgrep
# Windows (scoop)
scoop install ripgrep
# cargo (Rust)
cargo install ripgrep
기본 사용법
# 현재 디렉토리에서 재귀 검색 (기본 동작)
rg "TODO"
# 출력:
# src/app.ts:42: // TODO: 에러 핸들링 추가
# src/utils.ts:15: // TODO: 캐시 구현
# 대소문자 무시
rg -i "error"
# 파일 타입 필터
rg "import" --type ts # TypeScript 파일만
rg "def " --type py # Python 파일만
rg "SELECT" --type sql # SQL 파일만
# 특정 디렉토리에서 검색
rg "useState" src/components/
# 정규표현식 검색
rg "console\.(log|warn|error)" --type ts
# console.log, console.warn, console.error 모두 찾기
# 매칭되는 파일명만 출력
rg -l "TODO"
# 출력:
# src/app.ts
# src/utils.ts
고급 사용법
# 컨텍스트 라인 표시 (위아래 2줄)
rg "error" -C 2
# 특정 패턴 제외
rg "import" --type ts --glob '!**/*.test.ts' # 테스트 파일 제외
# JSON 출력 (다른 도구와 조합용)
rg "TODO" --json | jq 'select(.type == "match") | .data.lines.text'
# 파일별 매칭 수 카운트
rg -c "console.log" --type ts | sort -t: -k2 -rn
# 출력: (console.log가 많은 파일 순으로 정렬)
# src/debug.ts:15
# src/app.ts:8
# src/utils.ts:3
# 치환 (파일 수정 없이 결과만 미리보기)
rg "old_function" --replace "new_function"
# grep과의 속도 비교 (대규모 프로젝트에서)
# grep -r "pattern" . → 약 3초
# rg "pattern" → 약 0.3초 (10배 빠름)
fzf + ripgrep 조합
# ripgrep으로 검색 + fzf로 선택 + 에디터로 열기
rg --line-number "TODO" | fzf --delimiter : --preview 'cat -n {1} | head -{2}' | \
awk -F: '{print "+" $2, $1}' | xargs code -g
# TODO가 있는 줄을 퍼지 검색하고, 선택하면 VS Code에서 해당 줄로 이동
# 인터랙티브 ripgrep (fzf에서 실시간 검색)
rg_fzf() {
rg --line-number --color=always "$1" | \
fzf --ansi --delimiter : \
--preview 'cat -n {1}' \
--preview-window 'right:60%'
}
# 사용: rg_fzf "pattern"
도구 조합 치트시트
# API 응답에서 특정 필드 추출 후 퍼지 선택
http GET api.example.com/users | jq -r '.[].name' | fzf
# 로그 파일에서 에러 패턴 검색 후 컨텍스트 확인
rg "ERROR" logs/ -C 3 | fzf --ansi
# 프로세스 검색 후 종료
ps aux | fzf | awk '{print $2}' | xargs kill
# JSON 파일 찾기 + 내용 검색
rg -t json "api_key" | fzf
설치 요약
| 도구 | macOS | Ubuntu | Windows | 용도 |
|---|---|---|---|---|
| jq | brew install jq | apt install jq | scoop install jq | JSON 처리 |
| HTTPie | brew install httpie | apt install httpie | pip install httpie | HTTP 클라이언트 |
| fzf | brew install fzf | apt install fzf | scoop install fzf | 퍼지 검색 |
| ripgrep | brew install ripgrep | apt install ripgrep | scoop install ripgrep | 코드 검색 |
실전 팁
Ctrl+R(fzf 히스토리 검색)부터 익히세요: 이것 하나만으로도 터미널 생산성이 크게 향상됩니다. 긴 명령어를 다시 타이핑할 필요가 없습니다.jq는 API 테스트에 필수입니다:curl ... | jq '.data'처럼 API 응답을 즉시 파싱하여 원하는 필드만 확인할 수 있습니다.rg를grep -r대신 사용하세요:.gitignore를 자동 인식하므로node_modules나dist폴더를 건너뛰고, 속도도 훨씬 빠릅니다.- 도구를 조합하세요: 파이프(
|)로 도구를 연결하면 각 도구의 강점을 결합할 수 있습니다.rg | fzf,curl | jq | fzf같은 조합이 매우 강력합니다. - 셸 함수/별칭을 만드세요: 자주 쓰는 조합을
~/.bashrc나~/.zshrc에 함수로 등록하면, 한 단어로 복잡한 작업을 수행할 수 있습니다. - bat을 함께 설치하세요:
cat대신bat을 사용하면 구문 강조된 파일 내용을 볼 수 있어, fzf의 미리보기가 더 유용해집니다.