TL;DR
zsh는 셸이 시작될 때 여러 설정 파일을 순서대로 읽는다.
.zshenv→.zprofile→.zshrc→.zlogin→.zlogout순서이며, 셸 유형(로그인/비로그인, 인터랙티브/비인터랙티브)에 따라 읽히는 파일이 다르다. 대부분의 설정은.zshrc에, 환경 변수는.zshenv에 넣으면 된다.
AI-assisted
Source
1. 왜 설정 파일이 여러 개인가
zsh(또는 bash)가 실행되는 방식은 하나가 아니다.
- 로그인 셸 : 시스템에 처음 접속할 때 (SSH, 터미널 앱 첫 실행)
- 비로그인 셸 : 이미 로그인된 상태에서 새 셸을 여는 경우 (tmux 새 패인, 셸 안에서
zsh실행) - 인터랙티브 셸 : 사용자가 직접 명령어를 입력하는 셸
- 비인터랙티브 셸 : 스크립트 실행 시 자동으로 뜨는 셸 (cron, shell script)
상황마다 필요한 설정이 다르니 파일도 나뉘어 있다.
지금 쓰는 셸이 어떤 유형인지는 직접 확인할 수 있다.
echo $0 # 맨 앞에 '-'(-zsh)가 붙으면 로그인 셸
[[ -o login ]] && echo "login shell" # 로그인 셸이면 출력
[[ -o interactive ]] && echo "interactive shell" # 인터랙티브 셸이면 출력-o는 zsh의 셸 옵션 상태를 검사하는 문법이다. SSH로 갓 접속한 셸은 보통 로그인 + 인터랙티브, tmux 새 패인은 비로그인 + 인터랙티브, 스크립트 실행은 비인터랙티브로 잡힌다.
2. 로딩 순서
큰 흐름은 이렇다.
.zshenv → .zprofile → .zshrc → .zlogin → (셸 사용) → .zlogout
더 정확히는 각 단계마다 시스템 전역 파일이 먼저, 사용자 파일이 그다음으로 읽힌다.
/etc/zshenv → $ZDOTDIR/.zshenv (항상)
/etc/zprofile → $ZDOTDIR/.zprofile (로그인 셸)
/etc/zshrc → $ZDOTDIR/.zshrc (인터랙티브 셸)
/etc/zlogin → $ZDOTDIR/.zlogin (로그인 셸)
────────── 셸 사용 ──────────
$ZDOTDIR/.zlogout → /etc/zlogout (로그인 셸 종료)
$ZDOTDIR은 사용자 설정 파일이 모여 있는 디렉토리다(아래 4번 참고). 따로 지정하지 않으면 기본값이 홈 디렉토리($HOME)라서, $ZDOTDIR/.zshrc는 곧 익숙한 ~/.zshrc가 된다. 종료 단계인 .zlogout만 사용자 파일이 시스템 파일보다 먼저 읽힌다는 점은 기억해 둘 만하다.
시스템 전역 파일 경로
시스템 전역 파일은 배포판마다 위치가 다르다. macOS는
/etc/zshenv,/etc/zprofile,/etc/zshrc처럼/etc바로 아래에 두지만, Debian·Ubuntu·Arch 등은/etc/zsh/디렉토리 안에 둔다. 사용자 설정이 자꾸 덮어써진다면 이 전역 파일 경로부터 확인하면 된다.
3. 각 파일의 역할
.zshenv
- 모든 셸 유형에서 항상 읽힌다 (로그인/비로그인, 인터랙티브/비인터랙티브 전부)
- 환경 변수(
PATH,EDITOR,LANG등)를 설정하는 곳 - 스크립트 실행 시에도 읽히므로 출력을 생성하는 명령은 넣지 않는다
# ~/.zshenv
export EDITOR="nvim"
export LANG="en_US.UTF-8".zprofile
- 로그인 셸에서만 읽힌다
.zshrc보다 먼저 실행된다PATH추가, 로그인 시 1회만 실행할 설정을 넣는 곳- bash의
.bash_profile에 해당한다
# ~/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv)".zshrc
- 인터랙티브 셸에서만 읽힌다
- alias, 함수, 프롬프트, 플러그인, key binding 등 대부분의 설정이 여기에 들어간다
- 가장 많이 편집하는 파일
# ~/.zshrc
alias ls="eza --icons=always"
alias ll="eza -lah --icons=always"
source "$(brew --prefix)/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh"
source "$(brew --prefix)/share/zsh-autosuggestions/zsh-autosuggestions.zsh"
eval "$(starship init zsh)"
eval "$(zoxide init zsh)".zlogin
- 로그인 셸에서
.zshrc이후에 읽힌다 - 로그인 시 실행할 명령(시스템 정보 출력, 메일 확인 등)을 넣는 곳
.zprofile과 역할이 비슷해서 잘 사용하지 않는다
.zlogout
- 로그인 셸 종료 시 읽힌다
- 임시 파일 정리, 세션 종료 로그 등에 사용
4. 설정 파일 위치 바꾸기 — ZDOTDIR
지금까지는 설정 파일이 홈 디렉토리(~/.zshrc)에 있다고 가정했다. 하지만 ZDOTDIR 환경 변수를 설정하면 zsh는 사용자 설정 파일을 홈이 아닌 다른 디렉토리에서 찾는다. ~/.config/zsh처럼 한곳에 모아 두면 홈 디렉토리가 점(.) 파일로 어수선해지지 않고 설정을 묶어서 관리할 수 있다.
# ZDOTDIR을 지정하면 그 아래에서 설정 파일을 찾는다
export ZDOTDIR="$HOME/.config/zsh"
# 이후 .zprofile, .zshrc, .zlogin, .zlogout 은 모두 $ZDOTDIR 에서 로드된다.zshenv 만은 예외
ZDOTDIR을 설정하는 코드 자체가 어딘가에서 먼저 실행되어야 한다. 그래서.zshenv만은ZDOTDIR의 영향을 받지 않고 항상$HOME(또는/etc)에서 읽힌다.ZDOTDIR을 지정하는 줄은 반드시~/.zshenv에 둬야 하고, 나머지 파일은$ZDOTDIR안으로 옮기면 된다.
위치를 옮기고 나면 파일 배치는 다음과 같다.
| 파일 | 위치 |
|---|---|
.zshenv | ~/.zshenv (항상 홈에 고정) |
.zprofile, .zshrc, .zlogin, .zlogout | $ZDOTDIR (예: ~/.config/zsh) |
5. 셸 유형별 로딩 정리
| 파일 | 로그인 + 인터랙티브 | 비로그인 + 인터랙티브 | 비인터랙티브 (스크립트) |
|---|---|---|---|
.zshenv | O | O | O |
.zprofile | O | - | - |
.zshrc | O | O | - |
.zlogin | O | - | - |
.zlogout | O (종료 시) | - | - |
macOS 터미널 참고
macOS의 Terminal.app과 iTerm2는 새 탭/창을 열 때마다 로그인 셸로 실행한다. 그래서
.zprofile이 매번 읽힌다. 반면 tmux 새 패인이나 VS Code 내장 터미널은 비로그인 셸이므로.zprofile을 읽지 않는다.
6. 실전 가이드
어디에 뭘 넣어야 할지 모르겠다면 아래 기준을 따른다.
| 설정 내용 | 넣을 파일 |
|---|---|
환경 변수 (PATH, EDITOR) | .zshenv 또는 .zprofile |
Homebrew PATH (brew shellenv) | .zprofile |
| alias, 함수, 프롬프트 | .zshrc |
| 플러그인 (syntax-highlighting 등) | .zshrc |
| 로그인 시 1회 실행 명령 | .zprofile |
| 스크립트에서도 필요한 변수 | .zshenv |
PATH를 어디에 넣을까?
PATH는.zshenv에 넣으면 스크립트에서도 사용 가능하지만, macOS의/usr/libexec/path_helper가.zprofile단계에서 PATH를 재정렬하는 경우가 있다. Homebrew PATH 같은 것은.zprofile에 넣는 것이 안전하다.