[zoxide] cd 대신 쓰는 디렉터리 점프
![[zoxide] cd 대신 쓰는 디렉터리 점프](https://blog.kakaocdn.net/dna/Ou0PH/dJMcag0JSWP/AAAAAAAAAAAAAAAAAAAAAJrZZ5FPwrBeQujBiYATfQjtwKxVEHjfVnVUa4f3aSiu/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&expires=1788188399&allow_ip=&allow_referer=&signature=uJRlZwWguyO16dGRK553pp6DHsE%3D)
개발자 도구 · 터미널 & 환경 · 꿀팁
[zoxide] cd 대신 쓰는 디렉터리 점프
터미널에서 같은 프로젝트 폴더를 하루에도 수십 번 오가요. cd는 그때마다 전체 경로를 요구하죠. zoxide는 방문한 디렉터리를 기록해 두고 이름 일부만 치면 그리로 보내주는 도구예요. 예전의 autojump나 z 스크립트가 하던 일을 Rust로 다시 쓴 프로젝트고요. 설치와 셸 설정, 점수를 매기는 방식, 실제로 쓰는 명령과 환경 변수, 그리고 미리 알아둘 함정까지 순서대로 정리해요.
cd는 경로를 이미 알고 있어야 움직여요
cd의 문제는 기능이 부족한 게 아니라 사람에게 기억을 요구한다는 점이에요. ~/work/backend/services/payment-gateway 같은 경로를 매번 정확히 치거나, 탭 완성으로 한 단계씩 내려가야 해요. 상위로 올라갔다 다른 가지로 내려오는 왕복이 잦을수록 타이핑이 길어져요. 별칭을 만들어 두면 이번엔 별칭 이름이 기억나지 않는 상황이 와요.
이 문제를 푸는 접근은 오래전부터 있었어요. rupa/z 셸 스크립트, autojump, fasd 같은 도구들이 방문 기록을 데이터베이스에 쌓아 두고 z 키워드 한 번으로 점프시키는 방식을 만들었어요. zoxide는 같은 아이디어를 Rust로 다시 구현한 프로젝트예요. GitHub 스타 3만 8천 개가 넘는 인기 도구고 MIT 라이선스 오픈소스라 무료예요.
| 방식 | 동작 | 고려할 점 |
|---|---|---|
| cd + 탭 완성 | 경로를 한 단계씩 입력 | 깊은 경로일수록 타이핑이 늘어남 |
| alias 지정 | 자주 가는 곳에 이름 부여 | 폴더가 늘면 별칭도 같이 관리해야 함 |
| z·autojump·fasd | 방문 기록 기반 점프 | 셸 스크립트 구현, 셸별 지원 편차 |
| zoxide | 방문 기록 기반 점프 | 단일 바이너리, 주요 셸 전부 지원 |
기존 도구 대비 zoxide가 내세우는 차이는 두 갈래예요. 하나는 셸 스크립트가 아닌 컴파일된 바이너리라 어느 셸에서든 같은 코드가 돈다는 점이에요. 다른 하나는 지원 범위예요. bash·zsh·fish·PowerShell은 물론 Nushell·Elvish·Xonsh·Tcsh, 그리고 POSIX 셸까지 초기화 명령이 각각 준비돼 있어요.
설치하고 셸 설정 파일 맨 끝에 한 줄 넣으면 끝나요
설치 경로는 OS별 패키지 매니저로 대부분 해결돼요. macOS는 Homebrew, Windows는 winget·choco·scoop, 리눅스는 배포판 패키지나 공식 설치 스크립트를 씁니다. Rust 툴체인이 있다면 cargo로도 받아요.
# macOS
> brew install zoxide
# Windows
> winget install ajeetdsouza.zoxide
# Linux (공식 설치 스크립트)
> curl -sSfL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh
# 어느 OS든 (Rust 툴체인 필요)
> cargo install zoxide --locked
설치만으로는 z 명령이 생기지 않아요. zoxide는 셸 함수를 만들어 주는 초기화 명령을 따로 실행해야 해요. 이 줄을 셸 설정 파일에 넣어야 매 세션에 적용돼요. 공식 문서가 반복해서 강조하는 조건이 설정 파일의 맨 끝에 넣으라는 것이에요.
# ~/.zshrc 맨 끝
eval "$(zoxide init zsh)"
# ~/.bashrc 맨 끝
eval "$(zoxide init bash)"
# ~/.config/fish/config.fish 맨 끝
zoxide init fish | source
# PowerShell 프로파일 (echo $profile 로 위치 확인)
Invoke-Expression (& { (zoxide init powershell | Out-String) })
init 명령에는 옵션이 세 개 붙어요. --cmd는 명령 이름을 바꿔요. --cmd j로 초기화하면 명령이 j와 ji가 돼요. --cmd cd로 두면 cd 자체를 zoxide로 대체해요. --hook은 점수를 올리는 시점을 정해요. 기본값은 디렉터리가 바뀔 때마다인 pwd이고 나머지 선택지는 prompt(프롬프트가 뜰 때마다)와 none(올리지 않음)이에요. --no-cmd는 z와 zi를 아예 정의하지 않고 내부 함수인 __zoxide_z, __zoxide_zi만 노출해요. 자기 셸 함수로 감싸 쓰려는 경우를 위한 옵션이에요.
zoxide init 줄보다 앞에 있어야 해요. 공식 문서는 환경 변수가 init 호출 전에 설정되어 있어야 한다고 못 박고 있어요. 설정 파일 맨 끝 규칙과 함께 보면, 환경 변수 → init 순서로 배치하는 셈이에요.점수는 방문 횟수와 최근성을 곱해서 계산해요
zoxide의 랭킹은 frecency, 즉 frequency(빈도)와 recency(최근성)를 합친 개념이에요. 디렉터리는 처음 방문할 때 점수 1을 받고 방문할 때마다 1씩 올라가요. 그리고 검색 시점에 마지막 방문 시각을 따져 배수를 곱해요.
| 마지막 방문 시점 | 계산되는 frecency |
|---|---|
| 1시간 이내 | 점수 × 4 |
| 하루 이내 | 점수 × 2 |
| 일주일 이내 | 점수 ÷ 2 |
| 그보다 오래됨 | 점수 ÷ 4 |
1시간 이내와 일주일이 지난 경우의 배수 차이가 8배라, 오래전에 아무리 자주 갔던 폴더라도 오늘 작업 중인 폴더를 이기기 어려운 구조예요. 작업 대상이 바뀌면 랭킹도 며칠 안에 따라오는 셈이에요.
데이터베이스가 무한정 커지지 않게 하는 장치도 들어 있어요. 전체 점수 합이 _ZO_MAXAGE(기본 10000)를 넘으면 모든 디렉터리 점수를 일정 계수로 나눠 총합을 _ZO_MAXAGE의 90% 수준으로 낮춰요. 그 과정에서 점수가 1 아래로 떨어진 항목은 데이터베이스에서 빠져요. 문서는 이론상 최대 항목 수를 _ZO_MAXAGE의 4배로 잡되 실제로는 그보다 적다고 설명해요. 여기에 더해 파일 시스템에서 이미 사라졌고 90일이 지난 항목은 조회 과정에서 지연 정리돼요.
매칭 규칙 세 가지
점수만큼이나 중요한 게 어떤 경로가 후보에 오르는지예요. 규칙은 세 가지고, 이걸 모르면 왜 원하는 곳으로 안 가는지 이해가 안 되는 순간이 와요.
- 대소문자를 구분하지 않아요. Payment와 payment는 같게 취급돼요.
- 모든 키워드가 경로 안에 순서대로 있어야 해요.
z fo ba는 /foo/bar에 매칭되지만 /bar/foo에는 매칭되지 않아요. - 마지막 키워드의 마지막 조각이 경로의 마지막 조각과 일치해야 해요.
z bar는 /foo/bar를 잡지만 /bar/foo는 잡지 않아요.
세 번째 규칙이 실무에서 가장 자주 걸려요. 중간 디렉터리 이름만 치면 안 잡혀요. 목적지 폴더의 이름 일부를 마지막 키워드로 줘야 해요. 반대로 이 규칙 덕분에 상위 폴더가 얻어걸리는 오작동이 줄어드는 면도 있어요.
손에 익힐 명령은 사실상 z와 zi 둘이에요
z — 기본 점프
가장 많이 쓰는 형태예요. 키워드를 하나 주면 매칭되는 디렉터리 중 frecency가 가장 높은 곳으로 이동해요. 후보가 여럿이라 헷갈릴 때는 키워드를 두 개 이상 주면 범위가 좁아져요.
z foo # foo 에 매칭되는 최고 랭킹 디렉터리로 이동
z foo bar # foo 와 bar 를 모두 만족하는 디렉터리로 이동
z foo / # foo 로 시작하는 하위 디렉터리로 이동
z ~/foo # 일반 cd 처럼도 동작
z foo/ # 상대 경로로 이동
z .. # 한 단계 위로
z - # 직전 디렉터리로
주목할 부분은 아래쪽 네 줄이에요. z는 기록에 없는 경로를 받으면 그냥 cd처럼 동작해요. z ..이나 z - 같은 관용 표현도 그대로 받아요. cd를 쓰던 손버릇을 유지한 채 점프 기능만 얹는 형태예요. 초기화할 때 --cmd cd로 아예 cd를 대체하는 선택지가 성립하는 이유이기도 해요.
zi — fzf로 골라서 이동
키워드로 좁혀도 후보가 여러 개일 때 쓰는 명령이에요. zi foo를 치면 매칭된 목록이 fzf 화면으로 떠요. 방향키나 추가 타이핑으로 하나를 골라 이동해요. 어떤 후보들이 잡히고 있는지 눈으로 확인하는 용도로도 쓰여요. fzf가 설치돼 있어야 하며 문서가 명시한 최소 지원 버전은 v0.51.0이에요.
bash 4.4 이상·fish·zsh에서는 다른 경로도 있어요. z foo까지 친 뒤 공백을 넣고 탭을 누르면 인터랙티브 완성이 떠요. 명령을 바꾸지 않고 후보를 확인하는 순서예요.
zoxide query — 데이터베이스 들여다보기
랭킹이 예상과 다르게 나올 때 원인을 확인하는 명령이에요. 검색만 하고 이동은 하지 않아요. --list는 최고 점수 하나가 아니라 매칭된 전부를 보여줘요. --score는 계산된 점수를 경로와 함께 출력해요. 둘을 같이 쓰면 왜 저 폴더가 1등인지 숫자로 확인돼요. 나머지 옵션도 셋 있어요. --all은 삭제된 디렉터리까지 포함하고 --exclude는 특정 경로를 결과에서 빼요. --interactive는 zi와 같은 fzf 선택 화면을 띄워요.
# 매칭되는 항목 전부를 점수와 함께 확인
> zoxide query --list --score project
# 잘못 쌓인 항목 제거
> zoxide remove /path/to/old-project
# 특정 경로 점수를 직접 지정해서 추가
> zoxide add --score 100 /path/to/main-repo
zoxide add / remove / edit
add는 디렉터리를 데이터베이스에 넣거나 점수를 올려요. 평소에는 셸 훅이 알아서 호출해요. 직접 칠 일은 --score 옵션으로 초기 점수를 지정할 때 정도예요. remove는 특정 경로를 데이터베이스에서 지워요. 지운 뒤에도 계속 방문하면 다시 쌓여요. 영구적으로 제외하려면 아래 나오는 _ZO_EXCLUDE_DIRS 쪽을 봐야 해요. edit은 데이터베이스를 직접 편집하는 서브커맨드예요.
환경 변수 여섯 개가 나머지 동작을 정해요
설정 파일 형식은 따로 없고 환경 변수로 조정해요. 앞서 적었듯 전부 zoxide init 줄보다 앞에 있어야 해요.
| 변수 | 역할 |
|---|---|
| _ZO_DATA_DIR | 데이터베이스 저장 위치. 기본값은 리눅스·BSD가 $XDG_DATA_HOME 또는 $HOME/.local/share, macOS가 $HOME/Library/Application Support, 윈도우가 %LOCALAPPDATA% |
| _ZO_ECHO | 1로 두면 이동 전에 매칭된 경로를 출력 |
| _ZO_EXCLUDE_DIRS | 데이터베이스에 넣지 않을 경로를 glob 목록으로 지정. 구분자는 리눅스·macOS·BSD가 콜론, 윈도우가 세미콜론. 기본값은 $HOME |
| _ZO_FZF_OPTS | 인터랙티브 선택 시 fzf에 넘길 옵션 |
| _ZO_MAXAGE | 에이징 기준값. 기본 10000 |
| _ZO_RESOLVE_SYMLINKS | 1로 두면 심볼릭 링크를 실제 경로로 풀어서 저장 |
# ~/.zshrc — init 보다 위에 배치
export _ZO_ECHO=1
export _ZO_EXCLUDE_DIRS="$HOME:$HOME/private/*:/tmp/*"
export _ZO_RESOLVE_SYMLINKS=1
export _ZO_FZF_OPTS="--height 40% --reverse"
eval "$(zoxide init zsh)"
실제로 손대볼 만한 건 _ZO_EXCLUDE_DIRS와 _ZO_RESOLVE_SYMLINKS 정도예요. 앞쪽은 임시 폴더나 민감한 경로가 기록에 남지 않게 막아요. 뒤쪽은 심링크로 여러 이름을 가진 폴더가 서로 다른 항목으로 중복 집계되는 상황을 정리해요. 다만 문서가 짚듯 제외 목록을 설정한 뒤에는 이미 들어가 있던 항목을 zoxide remove로 따로 지워야 해요.
쓰던 z나 autojump 기록은 옮겨올 수 있어요
이미 다른 점프 도구를 쓰고 있었다면 데이터베이스를 가져오는 서브커맨드가 있어요. --from에 autojump나 z를 지정해요. z 포맷은 fasd·z·z.lua·zsh-z까지 커버해요.
# z 계열에서 가져오기
> zoxide import --from z "$HOME/.z"
# autojump 에서 가져오기 (경로만 넘어옴)
> zoxide import --from autojump "$HOME/.local/share/autojump/autojump.txt"
# 기존 데이터베이스에 합치기
> zoxide import --from z "$HOME/.z" --merge
두 가지 제약이 문서에 명시돼 있어요. 기본 동작은 현재 데이터베이스가 비어 있을 때만 성공해요. 이미 내용이 있으면 --merge를 붙여야 해요. 나머지 하나는 autojump 쪽 제약이에요. 경로만 넘어오고 점수는 넘어오지 않아요. 매칭 알고리즘이 너무 달라 점수를 그대로 옮기지 않는다는 설명이에요.
미리 알아두면 좋은 함정이 몇 가지 있어요
- init 줄은 설정 파일 맨 끝 — 다른 셸 플러그인이 프롬프트 훅을 건드리는 경우가 있어서 문서가 위치를 지정하고 있어요. 중간에 넣어 두면 훅이 덮여 점수가 안 쌓이는 상황이 생겨요.
- 환경 변수는 init 위에 — init 이후에 export하면 그 세션에서는 반영되지 않아요.
- 처음 며칠은 효과가 거의 없어요 — 방문 기록이 있어야 점프가 되니 초반에는 평소대로 이동해 데이터베이스를 채우는 기간이 필요해요. 급하다면 zoxide add로 자주 가는 경로를 미리 넣어두는 방법이 있어요.
- 마지막 조각 규칙 — 목적지 폴더 이름의 일부를 마지막 키워드로 줘야 해요. 중간 경로 이름만으로는 매칭되지 않아요.
- --cmd cd 는 셸을 가려요 — cd를 대체하는 옵션은 Nushell과 POSIX 셸에서는 동작하지 않는다고 문서에 적혀 있어요. cd를 바꾸면 스크립트나 다른 도구가 기대하는 동작과 어긋날 여지도 있어요. 처음에는 z를 그대로 쓰다가 나중에 판단하는 편이 무난해요.
- fzf 버전 — zi와 인터랙티브 선택은 fzf v0.51.0 이상을 요구해요. 배포판 패키지가 오래된 버전을 주는 경우가 있어요. zi가 이상하게 동작하면 fzf 버전부터 확인하는 순서가 빨라요.
- 여러 셸을 오가면 초기화도 각각 — 데이터베이스는 공유되지만 init 줄은 셸별 설정 파일에 각각 넣어야 해요.
같은 폴더를 반복해 오가는 사람에게 맞아요
zoxide가 유리한 조건은 뚜렷해요. 레포지토리나 서비스 폴더가 여러 개이고 경로가 깊으며 그중 일부를 매일 반복해 오가는 경우예요. 반대로 프로젝트가 한두 개뿐이거나 이미 별칭 몇 개로 충분히 굴러가는 환경이라면 굳이 도구를 하나 더 얹을 이유는 크지 않아요.
시작 순서는 짧아요. 패키지 매니저로 설치하고 셸 설정 파일 맨 끝에 init 한 줄을 넣은 다음, 며칠 평소대로 돌아다니며 기록을 쌓는 것까지가 전부예요. 그 뒤에 zoxide query --list --score로 랭킹이 어떻게 잡혔는지 한 번 보면 돼요. 기록에 남기고 싶지 않은 경로가 있으면 _ZO_EXCLUDE_DIRS를 손보고요. 기존에 z나 autojump를 쓰고 있었다면 import로 기록을 옮긴 뒤 예전 도구의 초기화 줄을 지우는 순서예요.
참고 자료
GitHub — ajeetdsouza/zoxide (README·설치) man zoxide(1) — 환경 변수·에이징·frecency man zoxide-init(1) — 셸별 초기화·옵션 zoxide Wiki — 매칭·에이징 알고리즘이 글은 직접 사용기가 아니라 zoxide 공식 저장소의 README·man page·위키 문서를 근거로 정리한 글이에요. 명령·옵션·기본값은 작성 시점 문서 기준이며 이후 릴리스에서 달라질 수 있어요.
'개발자 도구 > 터미널 & 환경' 카테고리의 다른 글
| [Starship] 셸이 뭐든 프롬프트를 통일하는 도구 (0) | 2026.07.31 |
|---|---|
| [fzf] 터미널 히스토리 검색이 달라지는 퍼지 파인더 활용법 (0) | 2026.07.20 |
| [Bun] Node와 npm을 대체하는 올인원 도구 (0) | 2026.07.01 |
| [tmux] SSH가 끊겨도 작업이 안 죽는 이유 (0) | 2026.06.24 |
| [Warp] 터미널을 블록 단위로 다루는 도구 (0) | 2026.06.15 |
📚 같이 보면 좋은
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 일정액의 수수료를 제공받습니다."