본문 바로가기
Tools2026년 9월 11일21분 읽기

현대 CLI 도구 셋업 — ripgrep·fd·bat·eza·zoxide·delta로 터미널 갈아끼우기

YS
김영삼
조회 7
현대 CLI 도구 셋업 — ripgrep·fd·bat·eza·zoxide·delta로 터미널 갈아끼우기

grep·find·cat·ls·cd를 ripgrep·fd·bat·eza·zoxide로 갈아끼우면, 같은 작업을 5~10배 빠르게 하면서 컬러·아이콘·문맥까지 얻는다. 핵심은 도구 6개를 설치하고 셸에 alias로 묶은 뒤 fzf 하나로 연결하는 것.

나는 3년째 이 조합을 매일 쓰는데, 되돌아갈 이유를 못 찾았다. 이 글은 각 도구가 실제로 뭘 바꾸는지, 어떤 alias와 설정을 쓰는지, 그리고 fzf와 어떻게 엮어서 "검색 → 미리보기 → 이동"을 한 번에 하는지를 실제 명령어로 정리한 것이다.

터미널에서 하루에 grep, find, cat, ls, cd를 몇 번이나 치는지 세어본 적 있는가. 나는 세어봤다. 수백 번이다. 그런데 이 기본 유틸들은 대부분 1970~80년대 설계 그대로다. 느리고, 기본값이 불친절하고, 컬러도 없다. Rust로 다시 쓰인 현대 대체 도구들은 이 지점을 정확히 노린다. 빠르고, 기본값이 똑똑하고, 눈에 잘 들어온다.

왜 기본 유틸을 갈아끼우나?

세 가지다 — 속도, 기본값, UX. 특히 속도 차이는 큰 저장소에서 극적이다. ripgrep은 .gitignore를 자동으로 존중하고 병렬로 도니까, node_modules가 낀 프로젝트에서 grep -r보다 몇 배 빠르다. fd는 정규식이 아니라 사람이 기대하는 방식으로 이름을 찾는다. 그리고 전부 컬러 출력이 기본값이라, 결과를 눈으로 훑는 시간이 줄어든다.

솔직히 말하면 나도 처음엔 "grep 잘 쓰는데 왜 바꿔"라고 생각했다. 결정적이었던 건 대형 모노레포에서 문자열 하나 찾는 데 grep이 20초씩 걸리던 때였다. rg로 바꾸니 1초 안쪽. 그날 바로 전부 깔았다.

대체 도구대신하는 것언어핵심 이득기본 명령
ripgrepgrep -rRustgitignore 존중·병렬·초고속rg
fdfindRust직관적 문법·컬러·gitignorefd
batcatRust문법 강조·줄번호·git 표시bat
ezalsRust아이콘·git 상태·트리eza
zoxidecdRust빈도 학습·점프z
deltagit diff/lessRust문법 강조 diff·side-by-sidedelta

공통점이 보이는가. 전부 Rust다. 이건 우연이 아니라 흐름이다. 안전한 메모리 모델 위에서 병렬화가 쉽고, 단일 바이너리로 배포되니 의존성 지옥이 없다. 그래서 설치도 대개 바이너리 하나 떨어뜨리면 끝이다.

한 번에 설치하기

패키지 매니저 하나로 6개를 다 깔 수 있다. macOS면 Homebrew, 데비안/우분투면 apt(단 배포판이 오래되면 이름이 다르거나 없을 수 있다), Arch면 pacman이다. 여기 함정이 하나 있다 — 데비안 계열에서 batbatcat, fdfdfind라는 이름으로 깔린다. 다른 패키지와 이름이 겹쳐서 그렇다.

# macOS (Homebrew) — 가장 깔끔
brew install ripgrep fd bat eza zoxide git-delta

# Debian / Ubuntu (apt) — 이름 주의: batcat, fdfind
sudo apt update
sudo apt install ripgrep fd-find bat
# eza·zoxide·delta는 apt에 없거나 오래됨 → 아래 참고

# Arch Linux
sudo pacman -S ripgrep fd bat eza zoxide git-delta

# 크로스플랫폼 대안: cargo (Rust 툴체인 필요)
cargo install ripgrep fd-find bat eza zoxide git-delta
참고 데비안/우분투에서 batcat·fdfind로 깔렸다면, ~/.local/bin에 심볼릭 링크를 만들어 이름을 정상화하는 게 편하다: ln -s $(which batcat) ~/.local/bin/bat, ln -s $(which fdfind) ~/.local/bin/fd. eza·zoxide·delta는 apt 버전이 낡았거나 없으니 GitHub 릴리스의 .deb을 받거나 cargo로 까는 걸 권한다.

ripgrep — grep을 대체하는 검색기

ripgrep(rg)은 재귀 검색을 기본으로 하고, .gitignore·.ignore·숨김 파일을 자동으로 건너뛰며, 병렬로 돈다. 그래서 grep -rn "패턴" .이 하던 일을 그냥 rg 패턴 한 줄로 한다. 옵션을 안 붙여도 줄번호·파일명·컬러가 다 나온다.

내가 매일 쓰는 패턴 몇 개를 보자. 특히 -t(타입 필터)와 -g(글롭)는 grep으로는 번거로운 걸 한 방에 해결한다.

# 기본: 현재 트리 전체에서 재귀 검색 (gitignore 자동 존중)
rg "useState"

# 파일 타입으로 제한 (py, js, rust, go … rg --type-list로 목록 확인)
rg -t py "def process"

# 글롭으로 범위 지정 + 대소문자 스마트(-S: 소문자면 무시, 대문자 있으면 구분)
rg -S "TODO" -g "*.ts" -g "!*.test.ts"

# 매치 앞뒤 문맥 3줄 (-C), 파일명만 (-l), 개수만 (-c)
rg -C 3 "panic!"
rg -l "deprecated"

# 정규식 + 치환 미리보기 (실제 파일은 안 건드림, 출력만 치환)
rg "foo_(\w+)" -r "bar_\$1"

# gitignore 무시하고 전부 뒤지기 (-u 반복할수록 더 뒤짐: -uu 숨김, -uuu 바이너리까지)
rg -uu "secret"

함정 하나. rg는 기본적으로 gitignore된 파일을 안 뒤진다. 그래서 "분명 있는데 안 나와요" 하면 십중팔구 그 파일이 gitignore에 걸린 거다. 이럴 땐 -u를 붙이면 된다. 이걸 모르고 한참 헤맨 적이 있어서 확실히 기억한다.

fd — find를 대체하는 파일 찾기

fd는 이름으로 파일을 찾을 때 find의 장황한 문법을 걷어낸다. find . -name "*.log" -type f가 그냥 fd -e log가 된다. 기본으로 정규식이 아니라 부분 일치 패턴을 쓰고, gitignore를 존중하고, 컬러로 출력한다.

# 이름에 config가 들어간 것 찾기 (부분 일치가 기본)
fd config

# 확장자로 (-e), 디렉터리만 (-t d), 파일만 (-t f)
fd -e md
fd -t d node_modules

# 특정 경로 아래에서 + 숨김 포함 (-H) + gitignore 무시 (-I)
fd -HI ".env" ~/projects

# 찾은 것마다 명령 실행 (-x: 각각, -X: 한 번에 모아서)
fd -e jpg -x convert {} {.}.webp      # 각 파일을 webp로
fd -e tmp -X rm                        # 임시파일 한꺼번에 삭제

# 최근 1일 내 수정된 파일 (--changed-within)
fd --changed-within 1d -t f

여기서 {}는 찾은 경로, {.}는 확장자를 떼어낸 경로다. 이 플레이스홀더가 find -exec{} \;보다 훨씬 읽기 편하다. 개인적으로 fd의 -x/-X 구분이 좋다 — 파일마다 실행할지, 한 번에 넘길지가 명확하다.

bat — cat을 대체하는 뷰어

bat은 파일을 볼 때 문법 강조·줄번호·git 변경 표시·자동 페이징을 얹어준다. 소스 코드를 터미널에서 훑을 때 컬러가 있고 없고는 체감 차이가 크다. 그냥 bat 파일명이면 된다. 파이프로 넘길 땐 자동으로 평범한 출력으로 바뀌니 스크립트를 깨지 않는다.

# 파일 보기 (문법 강조 + 줄번호 + git 표시)
bat src/main.rs

# 여러 파일 이어서, 특정 줄 범위만 (-r)
bat -r 40:80 server.js

# 테마 목록 보고 지정 (--list-themes / --theme)
bat --list-themes
bat --theme="Dracula" config.toml

# 다른 명령의 뷰어로: --help도 컬러로
tldr rg | bat -l man

# 스타일 최소화 (줄번호·표식 다 끄기) — 복붙용
bat -p main.py
주의 코드를 복사할 땐 줄번호가 같이 딸려오면 곤란하다. 이때 bat -p(plain)나 bat -pp로 장식을 끄자. 또 bat을 grep 결과 뷰어로 쓰면 좋은데, 뒤에서 fzf 연동에 이걸 그대로 활용한다.

eza — ls를 대체하는 목록

eza는 ls 자리에 아이콘·git 상태·트리 뷰·사람이 읽기 좋은 크기를 얹는다. 컬러가 파일 종류별로 다르게 나오고, --git으로 각 파일의 git 상태(수정·신규 등)를 옆에 표시한다. 참고로 eza는 예전 exa의 후속(활발히 유지되는 포크)이다.

# 롱포맷 + 숨김(-a) + 아이콘 + git 상태
eza -la --icons --git

# 사람이 읽기 좋은 크기 + 헤더 + 수정시간 정렬
eza -l --header --sort=modified

# 트리 뷰 (깊이 제한 -L), node_modules 등 무시
eza --tree --level=2 --git-ignore

# 디렉터리 먼저 묶어서
eza -l --group-directories-first

이걸 매번 길게 치기 싫으니 alias로 묶는데, 그건 아래 셸 통합 절에서 한꺼번에 다룬다.

zoxide — cd를 대체하는 점프

zoxide는 자주·최근 간 디렉터리를 학습해서, 전체 경로 대신 이름 조각만으로 점프하게 해준다. cd ~/work/projects/backend/src 대신 한 번 가본 뒤로는 z src 혹은 z back이면 그리로 뛴다. 내부적으로 "frecency"(frequency+recency) 점수로 후보를 고른다.

# 초기화 (셸 설정 파일에 넣는다 — 아래 통합 절 참고)
eval "$(zoxide init zsh)"   # bash면 zsh를 bash로

# 사용: 이름 조각으로 점프
z back            # 예: ~/work/projects/backend 로
z proj src        # 여러 키워드로 좁히기

# 인터랙티브 선택 (fzf 있으면 목록에서 고르기)
zi

# 현재까지 학습된 목록·점수 보기
zoxide query -ls

처음엔 좀 어색하다. 학습이 쌓이기 전엔 후보가 없으니까. 그런데 일주일만 쓰면 손가락이 cd를 잊는다. 나는 아예 cd를 zoxide로 덮어써서(--cmd cd) 무의식적으로 학습되게 해뒀다.

delta — git diff를 사람이 읽게

delta는 git의 diff·blame·grep 출력을 문법 강조·줄번호·side-by-side로 바꿔주는 페이저다. 도구를 새로 배우는 게 아니라 git 설정에 pager로 꽂기만 하면, 앞으로 모든 git diff·git show가 예뻐진다.

# ~/.gitconfig 에 추가
[core]
    pager = delta
[interactive]
    diffFilter = delta --color-only
[delta]
    navigate = true      # n/N 으로 파일 간 이동
    line-numbers = true
    side-by-side = true   # 좌우 비교 뷰
[merge]
    conflictStyle = zdiff3

side-by-side는 넓은 모니터에서 특히 좋다. 좁은 터미널에선 오히려 답답하니 취향껏 끄면 된다. delta를 붙인 뒤로 diff를 읽다가 놓치는 실수가 확 줄었다.

셸 통합 — alias와 초기화

도구를 깔았으면 셸 설정 파일(~/.zshrc 또는 ~/.bashrc)에 alias와 초기화를 넣어야 진짜 손에 붙는다. 핵심은 기존 습관(ls, cat, cd)을 그대로 치면 새 도구가 뜨게 덮는 것. 단, 원본이 필요할 때를 위해 탈출구(\ls 또는 command ls)도 알아두자.

# ~/.zshrc (bash면 zsh→bash로 바꾸면 됨)

# --- eza로 ls 대체 ---
alias ls='eza --icons --group-directories-first'
alias ll='eza -la --icons --git --group-directories-first'
alias lt='eza --tree --level=2 --icons --git-ignore'

# --- bat로 cat 대체 (평문 필요하면 \cat) ---
alias cat='bat --paging=never'
export BAT_THEME="ansi"        # 터미널 테마 따라감

# --- fd / rg 기본 옵션 ---
alias find='fd'                # 습관 교정용(원본은 \find)
export RIPGREP_CONFIG_PATH="$HOME/.ripgreprc"

# --- zoxide: cd 자체를 덮어쓰기 ---
eval "$(zoxide init zsh --cmd cd)"   # 이제 cd 가 곧 z

# 적용
# source ~/.zshrc

ripgrep은 ~/.ripgreprc에 기본 옵션을 박아둘 수 있다. 나는 스마트 케이스와 숨김 포함, 그리고 특정 폴더 제외를 넣어둔다.

# ~/.ripgreprc
--smart-case
--hidden
--glob=!.git/*
--glob=!node_modules/*
--max-columns=200
--max-columns-preview

fzf 연동 — 검색·미리보기·이동을 하나로

fzf는 퍼지 파인더인데, 위 도구들과 엮으면 "타이핑하면서 실시간으로 목록을 좁히고, 옆에 미리보기가 뜨고, 고르면 그 자리로 간다"가 된다. 핵심은 fzf가 목록을 만드는 소스로 fd·rg를, 미리보기 렌더러로 bat·eza를 쓰게 하는 것이다.

# ~/.zshrc — fzf 기본 소스와 미리보기를 fd/bat로

# 파일 목록 소스를 fd로 (숨김 포함, .git 제외)
export FZF_DEFAULT_COMMAND='fd --type f --hidden --exclude .git'
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"

# Ctrl-T(파일 삽입) 미리보기: 파일은 bat, 디렉터리는 eza 트리
export FZF_CTRL_T_OPTS="--preview '
  if [ -d {} ]; then eza --tree --color=always {} | head -200;
  else bat -n --color=always --line-range :200 {}; fi'"

# Alt-C(디렉터리 이동) 소스와 미리보기
export FZF_ALT_C_COMMAND='fd --type d --hidden --exclude .git'
export FZF_ALT_C_OPTS="--preview 'eza --tree --color=always {} | head -200'"

# fzf 키바인딩·자동완성 로드 (설치 위치는 배포판마다 다름)
source <(fzf --zsh)   # 최신 fzf. 구버전은 ~/.fzf.zsh 를 source

이제 진짜 강력한 조합. rg + fzf + bat으로 "코드베이스 전체를 라이브 검색하면서 매치 주변을 미리보기"하는 함수를 하나 만들어 두면, IDE 없이도 코드 탐색이 된다.

# 라이브 grep: 타이핑할 때마다 rg 재실행, 오른쪽에 bat 미리보기, Enter로 편집기 열기
rgf() {
  local file line
  IFS=: read -r file line _ < <(
    rg --line-number --no-heading --color=always --smart-case "${1:-}" |
      fzf --ansi \
          --delimiter : \
          --preview 'bat --color=always {1} --highlight-line {2} --line-range $(( {2}>10 ? {2}-10 : 1 )):+40' \
          --preview-window 'up,60%,border-bottom'
  )
  [ -n "$file" ] && ${EDITOR:-vim} "+$line" "$file"
}

rgf 함수는 내가 제일 자주 쓰는 물건이다. rgf useEffect라고 치면 코드베이스 전체에서 그 단어가 든 줄이 뜨고, 화살표로 옮길 때마다 오른쪽에 해당 파일의 그 줄 주변이 bat으로 강조되어 보인다. Enter를 누르면 편집기가 그 줄에서 바로 열린다. zoxide의 zi도 내부적으로 fzf를 써서 디렉터리를 골라 점프하니, 셋을 합치면 파일·디렉터리·코드 세 축의 탐색이 전부 퍼지 파인더 하나로 통일된다.

전환 로드맵 — 무리 없이 갈아타기

한 번에 다 바꾸면 손이 헷갈린다. 순서를 두는 게 좋다. 내가 남들에게 권하는 순서는 이렇다.

  1. rg와 fd부터. 이 둘은 습관을 안 건드리고 새 명령을 추가하는 거라 부작용이 없다. 속도 이득이 가장 크게 체감된다.
  2. bat를 cat alias로. 다만 스크립트에서 cat을 쓸 땐 \cat이나 command cat을 쓰도록 몸에 익히자.
  3. eza를 ls/ll로. 아이콘을 보려면 Nerd Font가 깔린 터미널이어야 한다(안 깔면 네모가 뜬다).
  4. zoxide로 cd 대체. 학습이 쌓일 시간을 주자. 일주일이면 충분하다.
  5. delta는 gitconfig에 pager로. 명령을 새로 배울 게 없어서 마지막에 슬쩍 넣으면 된다.
  6. 마지막에 fzf로 전부 묶기. 위 함수들을 넣는 순간 되돌아갈 수 없게 된다.
참고 서버에 SSH로 들어가면 이 도구들이 없을 때가 많다. 그래서 alias로 grep·cat·ls 자체를 덮어쓰기보다, rg·bat·eza라는 새 이름으로 쓰고 ll 같은 축약만 alias로 두는 편이 원격 환경과 근육기억 충돌이 적다. 나는 ls만 eza로 덮고 나머지는 새 이름 그대로 쓴다.

자주 묻는 질문

ripgrep과 grep은 결과가 완전히 같은가?

아니다. rg는 기본으로 .gitignore와 숨김 파일을 건너뛰기 때문에, grep보다 결과가 적게 나올 수 있다. "있는데 안 나온다" 싶으면 rg -uu로 무시 규칙을 꺼라. 또 rg의 정규식은 기본이 Rust regex(PCRE 일부 기능 없음)라, 룩어라운드가 필요하면 -P(PCRE2)를 붙여야 한다.

bat로 cat을 덮으면 스크립트가 깨지지 않나?

대개 안 깨진다. bat은 출력이 터미널이 아니라 파이프/파일로 갈 때 자동으로 평문·무페이징 모드로 바뀌기 때문이다. 다만 확실히 하려면 alias에 --paging=never를 두고, 스크립트 안에서는 command cat이나 \cat으로 원본을 부르면 된다.

eza에서 아이콘이 네모(□)로 깨진다. 왜인가?

아이콘용 글리프가 없는 폰트를 쓰고 있어서다. eza의 --icons는 Nerd Font(예: FiraCode Nerd Font, JetBrainsMono Nerd Font)를 요구한다. 터미널 폰트를 Nerd Font로 바꾸면 정상 표시된다. 폰트를 못 바꾸는 환경이면 --icons를 빼면 된다.

zoxide를 쓰면 기존 cd는 완전히 못 쓰나?

아니다. --cmd cd로 덮어써도 절대경로·상대경로 cd는 그대로 동작하고, 거기에 "이름 조각 점프" 기능이 얹히는 것뿐이다. 순수 원본 cd가 필요하면 builtin cd를 쓰면 된다. 덮어쓰기가 부담되면 --cmd를 빼고 z라는 별도 명령으로만 쓰면 된다.

delta는 어떤 명령을 새로 외워야 하나?

거의 없다. delta는 git의 pager로 설정하는 거라, git diff·git show·git log -p를 평소대로 치면 자동으로 delta가 렌더한다. 새로 익힐 건 navigate=true일 때 n/N으로 파일 사이를 오가는 정도다.

이 도구들이 서버·CI 환경에서도 안전한가?

바이너리 자체는 안전하지만, alias로 grep·cat 같은 표준 명령을 덮어쓴 채 스크립트를 짜면 그 스크립트가 다른 환경에서 깨진다. 그래서 스크립트에는 항상 표준 명령(grep, cat, find)을 쓰고, 대화형 셸에서만 대체 도구를 쓰는 걸 원칙으로 삼는 게 좋다. CI에는 이 도구들이 없다고 가정하라.

전부 설치하면 디스크·메모리 부담이 큰가?

미미하다. 6개 다 합쳐도 바이너리 총합이 수십 MB 수준이고, 전부 단일 실행 파일이라 실행 중 상주하지도 않는다. 오히려 rg·fd는 병렬로 돌 뿐 메모리를 크게 쓰지 않게 설계돼 있어, 대형 저장소에서 grep/find보다 자원 효율이 좋은 경우가 많다.

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록