PATH 환경 변수 완벽 이해하기
터미널에 git이라고 치면 Git이 실행되고, python이라고 치면 Python이 실행됩니다. 그런데 이 프로그램들이 디스크 어딘가에 파일로 존재할 텐데, 운영체제는 어떻게 그걸 찾아서 실행하는 걸까요? 🤔
이걸 가능하게 해주는 게 바로 PATH 환경 변수입니다. 개발 환경을 셋업하다 보면 “PATH에 추가하세요”라는 안내를 자주 보게 되는데, 정확히 뭘 어디에 추가하라는 건지 모호하게 느껴질 때가 있죠. Homebrew를 설치할 때도, Mise를 설정할 때도, pyenv나 nvm을 쓸 때도 PATH 설정이 빠지지 않습니다.
이번 글에서는 PATH가 정확히 무엇이고, 어떤 원리로 동작하며, 어떻게 설정하고 관리하는지 처음부터 끝까지 살펴보겠습니다.
PATH란?
PATH는 운영체제의 환경 변수 중 하나로, 셸이 명령어를 찾을 때 탐색할 디렉토리 목록을 담고 있습니다. 터미널에서 어떤 명령어를 입력하면 셸은 PATH에 나열된 디렉토리를 순서대로 뒤져서 해당 이름의 실행 파일을 찾습니다.
예를 들어 git이라고 입력하면 셸은 이런 과정을 거칩니다.
- PATH에 등록된 첫 번째 디렉토리에서
git이라는 파일을 찾는다 - 없으면 두 번째 디렉토리를 찾는다
- 이걸 반복해서 찾으면 실행하고, 끝까지 못 찾으면 에러를 낸다
그래서 command not found 에러가 나는 건 프로그램이 설치되지 않았거나, 설치는 됐는데 PATH에 해당 디렉토리가 등록되지 않았기 때문인 경우가 많습니다.
PATH 확인하기
현재 PATH에 어떤 디렉토리가 등록되어 있는지 확인해볼까요?
echo $PATH
/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
한 줄로 쭉 이어져서 읽기가 좀 힘든데요. PATH는 디렉토리 경로를 콜론(:)으로 구분해서 나열한 문자열입니다. 콜론을 줄바꿈으로 치환하면 훨씬 보기 편합니다.
echo $PATH | tr ':' '\n'
/opt/homebrew/bin
/opt/homebrew/sbin
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
이제 각 디렉토리가 한 줄씩 보여서 어떤 경로가 등록되어 있는지 한눈에 파악할 수 있습니다.
디렉토리 순서가 중요하다
PATH에서 디렉토리의 나열 순서는 단순한 정렬이 아니라 우선순위를 의미합니다. 셸은 앞에 있는 디렉토리부터 먼저 탐색하기 때문에 같은 이름의 프로그램이 여러 경로에 있으면 가장 먼저 발견된 것이 실행됩니다.
이게 왜 중요한지 구체적인 예를 들어볼게요. macOS에는 시스템에 기본으로 깔려 있는 Python이 있고, Homebrew로 설치한 Python도 있을 수 있습니다.
/usr/bin/python3 --version
Python 3.9.6
/opt/homebrew/bin/python3 --version
Python 3.12.4
이때 PATH에서 /opt/homebrew/bin이 /usr/bin보다 앞에 있으면 python3을 입력했을 때 Homebrew 버전이 실행됩니다. 순서가 반대라면 시스템 기본 버전이 실행되겠죠.
특정 명령어가 실제로 어디에서 실행되는지 확인하려면 which 명령어를 쓰면 됩니다.
which python3
/opt/homebrew/bin/python3
더 자세한 정보가 필요하면 type -a 명령어로 PATH에 있는 동일한 이름의 프로그램을 전부 확인할 수 있습니다.
type -a python3
python3 is /opt/homebrew/bin/python3
python3 is /usr/bin/python3
Zsh를 쓰고 있다면 where 명령어도 같은 역할을 합니다. 타이핑이 더 짧아서 편하죠.
where python3
/opt/homebrew/bin/python3
/usr/bin/python3
위에서 아래로 내려올수록 우선순위가 낮은 것이고, 맨 위에 표시된 경로의 프로그램이 실제로 실행됩니다.
PATH에 디렉토리 추가하기
새로운 프로그램을 설치했는데 command not found가 나온다면 해당 프로그램이 있는 디렉토리를 PATH에 추가해야 합니다.
현재 셸 세션에서만 임시로 PATH를 변경하려면 터미널에서 바로 export 명령어를 사용합니다.
export PATH="/새로운/경로:$PATH"
여기서 $PATH는 기존 PATH 값을 의미하는데요. 새 경로를 기존 PATH 앞에 붙이면 우선순위가 높아지고, 뒤에 붙이면 낮아집니다.
# 새 경로를 가장 높은 우선순위로 추가
export PATH="/새로운/경로:$PATH"
# 새 경로를 가장 낮은 우선순위로 추가
export PATH="$PATH:/새로운/경로"
이렇게 터미널에서 직접 입력한 설정은 해당 터미널 창을 닫으면 사라집니다. 영구적으로 적용하려면 셸 설정 파일에 추가해야 합니다.
셸 설정 파일에 PATH 추가하기
PATH를 영구적으로 설정하려면 셸 설정 파일에 export 구문을 추가해야 합니다. .bashrc, .bash_profile, .zshrc, .zprofile 등 비슷한 파일이 여러 개 있어서 헷갈릴 수 있는데 간단하게 정리하면 이렇습니다.
macOS는 Catalina부터 기본 셸이 Zsh이기 때문에 Mac 사용자라면 ~/.zshrc에 넣으면 됩니다. Linux에서 Bash를 쓴다면 ~/.bashrc에 넣고 ~/.bash_profile에서 source해주면 되고요. 자세한 내용은 셸 설정 파일 총정리에서 다루고 있습니다.
# Homebrew
eval "$(/opt/homebrew/bin/brew shellenv)"
# 커스텀 스크립트 경로
export PATH="$HOME/bin:$PATH"
설정 파일을 수정한 후에는 새 터미널을 열거나 source 명령어로 현재 셸에 바로 적용할 수 있습니다.
source ~/.zshrc
자주 보는 PATH 디렉토리
개발자의 PATH에는 보통 어떤 디렉토리가 들어 있을까요? macOS와 Linux에서 자주 보는 경로를 정리해보겠습니다.
/bin—ls,cp,mv같은 기본 시스템 명령어/usr/bin—git,ssh,curl같은 사용자용 명령어/usr/local/bin— 사용자가 직접 설치한 프로그램 (Intel Mac에서 Homebrew가 쓰는 경로)/opt/homebrew/bin— Apple Silicon Mac에서 Homebrew가 패키지를 설치하는 경로/usr/sbin,/sbin— 시스템 관리용 명령어$HOME/bin또는$HOME/.local/bin— 사용자 개인 스크립트나 도구
Homebrew를 설치하면 brew shellenv 명령어가 이 경로들을 자동으로 PATH에 추가해줍니다. eval "$(/opt/homebrew/bin/brew shellenv)" 한 줄이 내부적으로 여러 환경 변수를 설정하는 거죠.
/opt/homebrew/bin/brew shellenv
export HOMEBREW_PREFIX="/opt/homebrew"
export HOMEBREW_CELLAR="/opt/homebrew/Cellar"
export HOMEBREW_REPOSITORY="/opt/homebrew"
export PATH="/opt/homebrew/bin:/opt/homebrew/sbin${PATH+:$PATH}"
export MANPATH="/opt/homebrew/share/man${MANPATH+:$MANPATH}:"
export INFOPATH="/opt/homebrew/share/info:${INFOPATH:-}"
런타임 버전 매니저와 PATH
Node.js, Python 같은 런타임의 버전을 관리하는 도구는 PATH를 교묘하게 활용합니다.
nvm은 Node.js 버전을 전환할 때 PATH 앞쪽에 해당 버전의 경로를 끼워 넣어서 그 버전이 우선 실행되게 만듭니다.
nvm use 20
Now using node v20.11.0 (npm v10.2.4)
which node
/Users/dale/.nvm/versions/node/v20.11.0/bin/node
pyenv도 비슷한 방식으로 동작하고요. Mise는 이런 도구들을 하나로 통합해서 Node.js, Python, Java 등 여러 런타임의 버전을 일관된 방식으로 관리해줍니다.
공통점은 PATH 조작을 통해 특정 버전의 바이너리가 시스템 기본 버전보다 먼저 발견되도록 한다는 겁니다. 그래서 이런 도구의 초기화 코드(eval 구문)는 셸 설정 파일의 아래쪽에 배치하는 게 좋습니다. 다른 PATH 설정보다 나중에 실행되어야 해당 경로가 PATH의 맨 앞에 오거든요.
# 다른 PATH 설정들...
export PATH="$HOME/bin:$PATH"
# 런타임 버전 매니저는 마지막에 (PATH 앞쪽에 경로를 추가하므로)
eval "$(/opt/homebrew/bin/brew shellenv)"
eval "$(mise activate zsh)"
command not found 문제 해결하기
개발 환경을 셋업하다 보면 분명히 설치했는데 command not found가 나오는 상황을 한 번쯤 겪게 됩니다. 이때 당황하지 말고 체계적으로 확인해보면 됩니다.
우선 해당 프로그램이 실제로 어디에 설치되어 있는지 찾아야 합니다.
find / -name "프로그램이름" -type f 2>/dev/null
너무 느리다면 설치 도구의 정보를 확인하는 게 빠릅니다.
# Homebrew로 설치한 경우
brew --prefix 프로그램이름
프로그램 위치를 찾았다면 그 경로가 PATH에 포함되어 있는지 확인합니다.
echo $PATH | tr ':' '\n' | grep "찾은/경로"
PATH에 없다면 셸 설정 파일에 해당 경로를 추가하면 되는데요. 수정 후 source ~/.zshrc를 실행하거나 새 터미널을 열어서 바꾼 걸 적용합니다.
그래도 문제가 해결되지 않을 때 확인해볼 게 몇 가지 있습니다.
오타부터 의심해보세요. PATH 경로에 오타가 들어가는 실수가 의외로 많습니다. 셸 설정 파일을 열어서 경로가 정확한지 눈으로 확인해보는 게 좋고요.
실행 권한도 확인해봐야 합니다. 파일이 존재해도 실행 권한이 없으면 명령어로 인식되지 않거든요.
ls -la /경로/프로그램이름
출력에서 x 권한이 보이지 않으면 chmod +x로 실행 권한을 부여합니다.
셸 설정 파일 간의 충돌도 생각해봐야 합니다. .zprofile과 .zshrc에서 PATH를 서로 다르게 설정하고 있지는 않은지, 여러 도구가 PATH를 덮어쓰고 있지는 않은지 점검해보세요.
PATH 설정 시 주의할 점
PATH를 관리할 때 몇 가지 주의해야 할 점이 있습니다.
현재 디렉토리(.)를 PATH에 넣지 않는 게 좋습니다. export PATH=".:$PATH" 같은 설정을 하면 현재 디렉토리에 있는 스크립트를 ./script.sh 대신 script.sh만으로 실행할 수 있어서 편리해 보이지만 보안 위험이 있습니다. 공격자가 자주 사용하는 명령어 이름(ls, git 등)으로 악성 스크립트를 심어놓으면 그걸 모르고 실행할 수 있기 때문이죠.
PATH가 너무 길어지지 않도록 관리하는 것도 신경 써야 합니다. 여러 도구를 설치하고 삭제하다 보면 이미 존재하지 않는 경로가 PATH에 남아 있는 경우가 생기는데요. 셸이 매번 존재하지 않는 디렉토리를 탐색하게 되니 미세하게 성능에 영향을 줄 수 있고, 무엇보다 디버깅할 때 혼란스럽습니다.
가끔 PATH에 중복된 경로가 쌓이는 것도 흔한 문제인데요. 터미널을 열 때마다 같은 경로가 계속 추가되는 상황은 보통 셸 설정 파일에서 중복 방지 없이 export PATH="...:$PATH"를 반복 호출할 때 일어납니다. 큰 문제는 아니지만 echo $PATH의 출력이 지저분해지죠.
마치며
PATH는 셸에서 명령어를 찾는 탐색 경로 목록이고, 순서가 곧 우선순위입니다. 새로운 도구를 설치한 후 command not found가 나오면 해당 도구의 디렉토리가 PATH에 포함되어 있는지부터 확인해보세요.
PATH 설정이 익숙해지면 Homebrew로 패키지를 관리하거나 Mise로 런타임 버전을 전환하는 작업이 훨씬 수월해질 겁니다. 터미널에서 무언가 동작하지 않을 때 당황하지 않고 원인을 추적할 수 있는 힘도 생기고요.
셸과 터미널을 더 효율적으로 사용하고 싶다면 Oh My Zsh로 터미널 생산성 높이기도 함께 읽어보시면 좋겠습니다. macOS 디렉토리 구조나 Unix/Linux 디렉토리 구조에 대한 글도 PATH에 등장하는 경로를 이해하는 데 도움이 될 거예요.
This work is licensed under
CC BY 4.0