터미널에서 파일 하나를 열려고 cd와 ls를 몇 번씩 반복한 경험은 누구에게나 있다. 긴 경로를 외우거나 방향키로 히스토리를 한참 거슬러 올라가는 일도 마찬가지다. fzf 퍼지 파인더는 이런 반복 작업을 대화형 검색 한 번으로 줄여주는 단일 바이너리 도구다. 파일 목록이든 명령 히스토리든 Git 브랜치든, 표준 입력으로 들어오는 무엇이든 실시간 필터링 창으로 바꿔준다. 이번 포스팅에서는 fzf 퍼지 파인더를 설치하는 방법부터 셸 단축키, 미리보기, Git·ripgrep 연동, 그리고 실무에서 바로 쓰는 커스텀 함수까지 단계별로 정리하고자 한다.
fzf 퍼지 파인더가 대체 뭐길래
fzf는 표준 입력으로 받은 목록을 대화형으로 좁혀서 원하는 항목을 골라주는 명령줄 퍼지 파인더다. 파일, 프로세스, Git 커밋, 환경 변수 등 줄 단위 텍스트라면 무엇이든 입력이 될 수 있고, 타이핑할 때마다 밀리초 단위로 후보를 걸러낸다. Go로 작성된 단일 바이너리라 의존성이 없고, GitHub 스타 8만 개를 넘겼다.
퍼지 매칭이라는 이름 그대로 정확한 문자열을 몰라도 된다. src/main/UserService.java를 찾고 싶으면 srvusr 정도만 쳐도 후보에 걸린다. 입력한 글자들이 순서대로 들어간 항목을 모두 올린 뒤 관련도 순으로 정렬하기 때문이다. 원리는 이렇게 단순한데, 이걸 파일 탐색이든 히스토리 검색이든 브랜치 전환이든 아무 목록에나 파이프로 꽂을 수 있다는 게 fzf의 진짜 강점이다. 자세한 소개는 공식 GitHub 저장소에서 확인할 수 있다.
3분이면 끝나는 fzf 설치와 셸 통합
fzf 설치는 패키지 매니저로 바이너리를 받고, 셸 설정 파일에 통합 스크립트 한 줄을 추가하면 끝난다. macOS와 Linux 모두 Homebrew를 쓰면 가장 간단하고, 배포판 기본 패키지 매니저로도 설치할 수 있다. 통합 스크립트를 넣어야 뒤에서 다룰 Ctrl-T, Ctrl-R 같은 단축키가 활성화된다.
# macOS / Linux (Homebrew)
brew install fzf
# Debian / Ubuntu
sudo apt install fzf
# Arch Linux
sudo pacman -S fzf
# Fedora
sudo dnf install fzfShellScript위 명령은 fzf 바이너리를 시스템에 설치한다. Homebrew는 macOS와 Linux 양쪽에서 동일하게 동작하므로 팀 환경을 맞추기 좋고, 배포판 패키지는 버전이 다소 낮을 수 있으니 최신 기능이 필요하면 Homebrew나 Git 설치를 권한다.
# Bash: ~/.bashrc 에 추가
eval "$(fzf --bash)"
# Zsh: ~/.zshrc 에 추가
source <(fzf --zsh)
# Fish: ~/.config/fish/config.fish 에 추가
fzf --fish | sourceShellScript이 통합 스크립트는 키 바인딩과 자동완성을 셸에 등록한다. fzf --zsh처럼 셸이 직접 설정을 출력하는 방식이라 별도 플러그인 파일을 관리할 필요가 없다. 설정을 추가한 뒤 셸을 새로 열거나 source ~/.zshrc로 다시 읽으면 fzf 퍼지 파인더의 단축키가 곧바로 살아난다.
손이 먼저 기억하는 세 개의 단축키

fzf 셸 통합을 켜면 Ctrl-T, Ctrl-R, Alt-C 세 개의 단축키가 생긴다. 각각 파일 붙여넣기, 히스토리 검색, 디렉터리 이동을 담당하며, 이 세 가지만 손에 익어도 터미널 이동 시간이 눈에 띄게 줄어든다. 별도 명령을 외울 필요 없이 입력 중 아무 때나 누르면 대화형 창이 뜬다.
# Ctrl-T : 현재 명령줄에 파일/디렉터리 경로를 검색해 삽입
vim <Ctrl-T> # 파일을 고르면 vim 뒤에 경로가 채워진다
# Ctrl-R : 셸 명령 히스토리를 퍼지 검색
<Ctrl-R> # gradle build 처럼 일부만 쳐도 과거 명령을 찾아준다
# Alt-C : 하위 디렉터리를 검색해 그 위치로 cd
<Alt-C> # 깊은 경로도 몇 글자로 이동ShellScriptCtrl-T는 명령을 다 치지 않은 상태에서 파일 경로만 대화형으로 끼워 넣을 때 쓴다. docker cp <Ctrl-T>처럼 명령을 조립하는 중간에 경로를 채우는 식이다. Ctrl-R은 방향키로 히스토리를 뒤지던 습관을 완전히 대체하며, 관련도 정렬과 텍스트 매칭을 지원한다. Alt-C는 선택한 디렉터리로 바로 이동시켜 준다. 세 단축키 모두 TAB으로 여러 항목을 다중 선택할 수 있어, 파일 여러 개를 한 번에 편집기로 넘기는 것도 가능하다. 참고로 Alt-C는 macOS 기본 터미널에서 Option 키가 Meta로 잡혀 있지 않으면 동작하지 않으니, iTerm2나 Ghostty에서 Option을 Esc+로 설정해두면 문제없이 쓸 수 있다.
iTerm2 에서 Option 키를 Esc+ 설정 변경하기
Settings → Profiles → Keys → Left Option key 를
Esc+로 변경
설정 변경 후 iterm2 터미널을 다시 시작해 준다.
FZF_DEFAULT_COMMAND로 검색 범위 길들이기

fzf가 기본으로 무엇을 검색할지는 FZF_DEFAULT_COMMAND 환경 변수로 정한다. 기본값은 시스템 find지만, fd나 ripgrep으로 바꾸면 .gitignore를 존중하고 숨김 파일 처리도 깔끔해진다. 검색 대상과 화면 모양을 미리 정해두면 매번 옵션을 붙이지 않아도 일관된 결과를 얻는다.
# ~/.zshrc 또는 ~/.bashrc
# fd로 기본 검색 (.gitignore 자동 반영, 경로 앞 ./ 제거)
export FZF_DEFAULT_COMMAND='fd --type f --strip-cwd-prefix'
# Ctrl-T도 동일하게 fd 사용
export FZF_CTRL_T_COMMAND="$FZF_DEFAULT_COMMAND"
# 공통 UI 옵션: 화면 40%, 위에서 아래 배치, 테두리 표시
export FZF_DEFAULT_OPTS="--height 40% --layout=reverse --border"ShellScriptFZF_DEFAULT_COMMAND에 fd --type f를 지정하면 파일만 후보로 올라오고, --strip-cwd-prefix가 경로 앞의 ./를 떼어 목록을 깔끔하게 만든다. FZF_DEFAULT_OPTS는 모든 fzf 호출에 공통으로 적용되는 옵션이라, 화면 높이나 레이아웃을 한 곳에서 통제할 수 있다. fd가 없다면 sudo apt install fd-find나 brew install fd로 먼저 설치한다.
–preview로 고르기 전에 미리 본다

--preview 옵션은 커서가 놓인 항목의 내용을 오른쪽 창에 실시간으로 띄운다. 파일을 열어보기 전에 내용을 확인할 수 있어, 비슷한 이름의 설정 파일이나 로그를 구분할 때 특히 유용하다. {} 자리표시자에 현재 선택된 줄이 들어가므로 어떤 명령이든 미리보기로 연결할 수 있다.
# bat으로 구문 강조된 파일 미리보기 (~3은 헤더 3줄 고정)
fzf --preview 'bat --color=always {}' --preview-window '~3'
# 디렉터리 구조를 트리로 미리보기
fzf --preview 'tree -C {}'
# 파일 유형만 간단히 확인
fzf --preview 'file {}'ShellScript첫 번째 예시는 bat으로 파일을 구문 강조해 보여주며, --preview-window '~3'은 스크롤과 무관하게 상단 3줄을 고정한다. bat은 cat을 대체하는 도구로 brew install bat으로 설치한다. {}는 fzf가 현재 하이라이트한 줄로 치환되기 때문에, 미리보기 명령만 바꾸면 파일 내용, 이미지 정보, JSON 포맷 등 무엇이든 옆 창에 띄울 수 있다.
Git과 fzf를 엮으면 브랜치 전환이 손에 붙는다

fzf 퍼지 파인더를 Git과 연결하면 브랜치 전환과 커밋 탐색을 대화형으로 처리할 수 있다. 브랜치 이름을 정확히 몰라도 몇 글자로 골라 바로 체크아웃하고, 커밋 히스토리는 미리보기 창에서 diff까지 확인하며 넘겨본다. 아래 함수를 셸 설정에 추가하면 fco, fshow 같은 짧은 명령으로 쓸 수 있다.
# 브랜치를 골라 체크아웃
fco() {
local branch
branch=$(git branch --all | grep -v HEAD | sed 's/^[* ]*//;s#remotes/[^/]*/##' \
| sort -u | fzf --preview 'git log --oneline --color=always {} | head -50') || return
git checkout "$branch"
}
# 커밋 히스토리를 미리보기와 함께 탐색
fshow() {
git log --graph --color=always \
--format="%C(auto)%h%d %s %C(black)%C(bold)%cr" |
fzf --ansi --no-sort \
--preview 'grep -o "[a-f0-9]\{7,\}" <<< {} | head -1 | xargs -I% git show --color=always %'
}ShellScriptfco는 로컬과 원격 브랜치를 모아 중복을 제거한 뒤 fzf로 넘기고, 미리보기 창에 해당 브랜치의 최근 커밋 50개를 띄운다. fshow는 그래프 로그를 fzf에 파이프하는데, --graph가 붙은 줄에는 *나 | 같은 그래프 문자가 앞에 오므로 필드 위치로 해시를 집으면 어긋난다. 그래서 미리보기에서 grep -o로 줄에서 7자리 이상 16진수(커밋 해시)만 뽑아 git show에 넘긴다. 더 정교한 Git 연동을 원한다면 저자가 만든 fzf-git.sh 스크립트를 그대로 가져다 쓰는 방법도 있다.
ripgrep + fzf로 코드베이스를 실시간으로 훑기

ripgrep과 fzf를 결합하면 코드베이스 전체를 타이핑하는 즉시 검색하고, 결과를 골라 바로 편집기로 점프할 수 있다. 핵심은 fzf의 자체 필터링을 끄고(--disabled), 입력이 바뀔 때마다 ripgrep을 다시 실행(reload)하도록 바인딩하는 것이다. 이렇게 하면 fzf가 검색 UI 역할만 하고 실제 매칭은 ripgrep이 담당한다.
# 입력할 때마다 ripgrep을 재실행하고, Enter로 vim의 해당 줄로 점프
rfv() {
local RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case"
: | fzf --ansi --disabled \
--bind "start:reload:$RG_PREFIX {q}" \
--bind "change:reload:$RG_PREFIX {q}" \
--delimiter : \
--preview 'bat --color=always {1} --highlight-line {2}' \
--bind 'enter:become(vim {1} +{2})'
}ShellScript--disabled는 fzf가 결과를 다시 필터링하지 않게 막아, 검색을 온전히 ripgrep에 맡긴다. change:reload 바인딩은 사용자가 글자를 칠 때마다 {q}(현재 쿼리)로 ripgrep을 다시 돌리는 부분이고, enter:become(vim {1} +{2})는 선택한 결과의 파일({1})을 해당 줄 번호({2})로 열어준다. --delimiter :를 지정한 덕분에 rg가 출력하는 파일:줄:열:내용 형식이 콜론 기준으로 나뉘어 {1}, {2}가 각각 파일과 줄 번호에 정확히 대응한다. 이 패턴의 전체 설명은 공식 ripgrep 통합 문서에 자세히 정리되어 있다.
여기서 한 가지 짚어둘 점은, 이 방식이 grep 파이프라인을 매 입력마다 다시 실행한다는 것이다. 프로젝트가 수십만 줄 규모여도 ripgrep 자체가 빠르기 때문에 체감 지연은 거의 없지만, node_modules나 빌드 산출물이 인덱싱되면 결과가 지저분해진다. rg는 기본으로 .gitignore를 존중하므로 대부분 알아서 걸러지고, 그래도 남는 경로는 --glob '!target/*' 같은 옵션을 RG_PREFIX에 추가해 제외하면 된다.
fzf 퍼지 파인더와 비슷한 도구, 뭘 골라야 하나

fzf는 범용 퍼지 파인더이고, 비슷해 보이는 다른 도구들은 각자 특정 작업에 특화되어 있다. 파일 검색만 필요하면 fd, 텍스트 검색이면 ripgrep, 디렉터리 점프면 zoxide가 더 좁고 빠른 선택지다. fzf는 이들을 대체한다기보다, 이들의 출력을 대화형으로 감싸는 계층에 가깝다.
| 도구 | 주 용도 | fzf와의 관계 |
|---|---|---|
| fzf | 범용 대화형 퍼지 파인더 | 다른 도구 출력을 감싸는 UI |
| fd | 파일·디렉터리 검색 | FZF_DEFAULT_COMMAND로 결합 |
| ripgrep | 파일 내용 텍스트 검색 | reload 바인딩으로 결합 |
| zoxide | 자주 간 디렉터리 점프 | 보완 관계 (zi가 fzf 사용) |
표에서 보듯 이들은 경쟁이 아니라 조합 관계다. fd가 파일 목록을 만들면 fzf가 그 위에서 선택 UI를 얹고, ripgrep이 매칭을 찾으면 fzf가 결과를 넘겨보게 한다. zoxide조차 대화형 모드(zi)에서 내부적으로 fzf를 호출한다. 즉 fzf 퍼지 파인더 하나를 익혀두면 나머지 모던 CLI 도구들과 자연스럽게 맞물린다. fzf를 fd·bat·zoxide와 함께 처음부터 세팅하는 과정은 모던 CLI 도구 필수 세팅 2026 글에 설치부터 연동까지 정리해 두었으니 함께 참고하면 좋다.
실무에서 손이 자주 가는 커스텀 함수 모음

fzf는 셸 함수로 감싸 짧은 명령으로 만들어 둘 때 제일 쓸모가 커진다. 프로세스 종료나 Docker 컨테이너 접속처럼 인자를 외워야 하는 작업을 대화형으로 바꾸면, 명령 형식을 기억할 필요 자체가 사라진다. 아래 함수들을 셸 설정에 넣어두면 백엔드 개발자의 일상 작업 대부분을 커버한다.
# 프로세스를 골라 종료
fkill() {
local pid
pid=$(ps -ef | sed 1d | fzf -m | awk '{print $2}') || return
echo "$pid" | xargs kill -"${1:-9}"
}
# 실행 중인 Docker 컨테이너에 접속
fdocker() {
local cid
cid=$(docker ps --format '{{.Names}}\t{{.Image}}' | fzf | awk '{print $1}') || return
docker exec -it "$cid" /bin/sh
}ShellScriptfkill은 프로세스 목록을 fzf로 넘겨 다중 선택(-m)으로 여러 프로세스를 한 번에 종료하고, 신호 번호를 인자로 받아 기본값 9를 쓴다. fdocker는 실행 중인 컨테이너 이름과 이미지를 보여준 뒤 선택한 컨테이너에 셸로 접속한다. 자동완성이 필요할 때는 명령 뒤에 ** 트리거를 붙이는 방법도 있다. 예를 들어 kill -9 **<TAB>을 치면 fzf 퍼지 파인더 창이 떠 종료할 프로세스를 고르게 해준다.
자주 묻는 질문 (FAQ)
fzf와 fd, ripgrep은 어떻게 다른가?
fzf는 표준 입력으로 받은 목록을 대화형으로 걸러주는 범용 퍼지 파인더이고, fd는 파일 검색, ripgrep은 파일 내용 검색에 특화된 도구다. 셋은 경쟁 관계가 아니라 조합해서 쓴다. fd나 ripgrep이 만든 결과를 fzf가 대화형 UI로 감싸는 구조다.
fzf를 설치했는데 Ctrl-R 단축키가 안 먹는다.
셸 통합 스크립트를 설정 파일에 넣지 않았을 가능성이 크다. Zsh라면 source <(fzf --zsh), Bash라면 eval "$(fzf --bash)"를 각각 ~/.zshrc, ~/.bashrc에 추가하고 셸을 다시 열어야 한다. 바이너리 설치와 단축키 활성화는 별개 단계다.
–preview 창이 비어 있거나 깨져 보인다.
미리보기 명령에 쓴 도구가 설치되지 않았거나 경로가 맞지 않는 경우다. bat을 쓴다면 먼저 brew install bat으로 설치하고, {} 자리표시자가 올바른 파일 경로로 치환되는지 확인한다. 이미지나 바이너리 파일은 file {} 정도로 유형만 표시하는 편이 안전하다.
회사 서버처럼 Homebrew를 못 쓰는 환경에서는 어떻게 설치하나?
Git 클론 방식이 가장 이식성이 좋다. git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf 후 ~/.fzf/install을 실행하면 홈 디렉터리에 바이너리와 셸 통합이 함께 설치된다. root 권한이나 패키지 매니저가 없어도 동작한다.
fzf가 검색 결과를 이상하게 정렬한다. 정렬을 끄고 싶다.
--no-sort 옵션을 붙이면 입력받은 순서를 그대로 유지한다. Git 로그나 히스토리처럼 시간 순서가 중요한 목록을 넘길 때 유용하다. 반대로 관련도 정렬이 기본 동작이므로, 정렬이 필요 없을 때만 선택적으로 끄면 된다.
마치며

지금까지 fzf 퍼지 파인더의 설치부터 단축키, 미리보기, Git·ripgrep 연동, 커스텀 함수까지 정리해 보았다. 개인적으로 fzf를 처음 깔았을 때는 Ctrl-R 하나만 쓰다가, 어느 순간 fco로 브랜치를 넘나들고 rfv로 코드베이스를 훑고 있는 나를 발견했다. 특히 마이크로서비스 여러 개를 오가며 작업할 때 브랜치 이름을 일일이 치던 습관이 사라진 게 가장 큰 변화였다.
fzf는 한 번에 다 익히는 도구가 아니라, 반복되는 불편을 느낄 때마다 함수 하나씩 늘려가는 도구에 가깝다. 오늘 소개한 함수 중 두세 개만 셸 설정에 넣어두고 일주일만 써봐도, 손이 먼저 fzf를 찾는 순간이 온다. 그때부터가 진짜 시작이다.
