본문 바로가기

복사금지 블로그 짜증나서 만든 개발문서

sudo 만 붙이면 command not found, 환경변수까지 사라질 때 — sudo 질문 6가지

반응형

환경  sudo 1.9 · Ubuntu·Debian 기본 sudoers · 2026-09-25 확인

sudo 는 권한만 바꾸는 게 아니라 명령이 뜰 환경을 새로 만듭니다. secure_path, env_reset, -E, 리다이렉션, cd, -s 와 -i 까지 자주 묻는 순서로 정리했습니다.

터미널에선 되는데 sudo 를 붙이면 command not found 가 나요

제일 흔한 질문입니다. nvm 으로 깐 node, pyenv 의 python, ~/.local/bin 에 넣어 둔 도구처럼 내 PATH 에만 있는 명령이 주로 걸립니다. which node 는 경로를 잘 보여 주는데 sudo node 는 못 찾는다고 합니다.

원인은 secure_path 입니다. sudoers 에 이 값이 있으면 sudo 는 내 PATH 대신 이 값을 PATH 로 씁니다. 명령을 찾는 것도 이 PATH 로 합니다. 우분투·데비안의 기본 sudoers 에는 이 줄이 들어 있고, 값은 /usr/local/sbin 부터 /bin 까지 시스템 디렉터리뿐입니다. 홈 아래 경로는 당연히 없습니다.

secure_path 가 있는 데는 이유가 있습니다. /usr/sbin 처럼 일반 사용자 PATH 에 없는 관리 명령을 sudo 가 찾게 하려는 것, 그리고 권한이 낮은 사용자가 PATH 를 조작해 root 로 엉뚱한 프로그램을 띄우지 못하게 막으려는 것입니다. 그러니 끄는 것보다는 우회하는 쪽이 맞습니다.

가장 간단한 우회는 전체 경로를 주는 겁니다. sudo "$(command -v node)" 처럼 지금 셸이 찾은 경로를 그대로 넘기면 됩니다. 매번 쓰는 도구라면 /usr/local/bin 에 링크를 걸거나, visudo 로 secure_path 에 디렉터리를 더합니다. 이때도 남이 쓸 수 있는 디렉터리는 넣지 않습니다.

# 지금 적용 중인 secure_path 확인
sudo -l | grep -o 'secure_path=[^,]*'

# 내 셸이 찾은 경로를 그대로 넘긴다
sudo "$(command -v node)" server.js

# 자주 쓰는 도구면 시스템 경로에 링크
sudo ln -s "$(command -v node)" /usr/local/bin/node

sudo 는 명령을 내 PATH 가 아니라 secure_path 로 찾습니다

sudo 가 명령을 못 찾으면 내 PATH 가 아니라 secure_path 를 봐야 합니다.

export 해 둔 환경변수가 sudo 안에서는 비어 있어요

export API_KEY=... 를 해 두고 sudo ./deploy.sh 를 돌리면 스크립트 안에서 API_KEY 가 비어 있습니다. 프록시 설정인 HTTP_PROXY 가 sudo apt 에서만 안 먹는 것도 같은 이유입니다.

sudo 는 기본으로 env_reset 이 켜져 있습니다. 명령을 새로 만든 최소한의 환경에서 돌리는 설정입니다. 남는 건 TERM·PATH·HOME·MAIL·SHELL·LOGNAME·USER 와 SUDO_ 로 시작하는 변수 정도이고, 여기에 env_keep 목록에 든 변수만 내 환경에서 옮겨 갑니다. HOME·SHELL·USER 같은 값은 내 것이 아니라 대상 사용자, 보통 root 기준으로 채워집니다.

필요한 변수만 골라 넘기면 됩니다. --preserve-env=API_KEY,HTTP_PROXY 처럼 쉼표로 이어 적거나, sudo API_KEY="$API_KEY" ./deploy.sh 처럼 명령 앞에 값을 적습니다. 다만 둘 다 sudoers 가 허락해야 통합니다. 명령이 ALL 로 허용된 사용자라면 SETENV 가 따라오기 때문에 대개 됩니다. 특정 명령만 허용받은 계정이면 거부될 수 있습니다.

프록시 변수처럼 늘 넘겨야 하는 것은 sudoers 에 env_keep 으로 올려 두는 편이 깔끔합니다. visudo 로 /etc/sudoers.d/ 아래 파일을 하나 만들어 Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY" 를 적습니다.

export API_KEY=abc123
sudo sh -c 'echo "[$API_KEY]"'
# []                        ← env_reset 으로 사라졌다

# 필요한 것만 골라 넘긴다
sudo --preserve-env=API_KEY sh -c 'echo "[$API_KEY]"'
# [abc123]

# 늘 넘길 변수는 sudoers 에 등록
sudo visudo -f /etc/sudoers.d/proxy
# Defaults env_keep += "HTTP_PROXY HTTPS_PROXY NO_PROXY"

통째로 넘기지 말고 이름을 골라 넘깁니다

sudo 는 환경을 새로 만듭니다. 넘길 변수는 이름으로 골라 줍니다.

그럼 sudo -E 로 전부 넘기면 되지 않나요?

되는 경우도 있고 아닌 경우도 있습니다. -E 는 지금 환경을 그대로 보존해 달라는 요청입니다. 이 요청이 받아들여지려면 sudoers 에서 setenv 옵션이나 SETENV 태그가 허락돼 있어야 합니다. 권한이 없으면 sudo 가 오류를 내고 멈춥니다.

허락된 경우에도 PATH 는 여전히 secure_path 로 덮입니다. -E 를 붙였는데도 첫 번째 질문의 command not found 가 그대로라면 이 때문입니다. 명령 찾기 문제는 -E 로 풀리지 않습니다.

그리고 -E 는 필요 없는 것까지 전부 root 로 들고 갑니다. 내 HOME 이나 XDG 경로가 따라가면 root 가 만든 파일이 내 홈에 생겨서, 나중에 내 계정으로 그 파일을 못 고치는 일이 생깁니다. 캐시 디렉터리가 root 소유가 돼서 npm 이나 pip 가 권한 오류를 내는 사고가 대개 이 경로로 옵니다.

그래서 -E 는 잠깐 확인할 때만 쓰고, 스크립트나 cron 에는 --preserve-env=이름 으로 필요한 변수만 적어 두는 게 낫습니다. 나중에 읽는 사람도 무엇이 넘어가는지 한눈에 봅니다.

-E 를 붙여도 PATH 는 secure_path 입니다. 스크립트에는 --preserve-env=이름 으로 적습니다.

sudo echo 로 /etc 에 쓰는데 Permission denied 가 나요

sudo echo 'vm.swappiness=10' > /etc/sysctl.d/99-swap.conf 는 sudo 를 붙였는데도 거부됩니다. 권한 문제처럼 보이지만 원인은 순서입니다.

> 는 sudo 가 처리하는 게 아니라 지금 쓰고 있는 셸이 처리합니다. 셸은 sudo 를 실행하기 전에 먼저 파일을 열어 출력을 연결하고, 그다음에 sudo echo 를 띄웁니다. 파일을 여는 건 내 계정이니 /etc 에 쓸 수 없고, root 로 도는 건 echo 뿐입니다. 파이프 뒤의 >> 도 마찬가지입니다.

해법은 파일을 여는 쪽을 root 로 돌리는 겁니다. 제일 흔한 건 tee 입니다. 출력은 내 셸에서 만들고, 파일 쓰기는 sudo tee 가 합니다. 덧붙이려면 tee -a 를 쓰고, 화면에 똑같은 내용이 또 찍히는 게 싫으면 뒤에 > /dev/null 을 붙입니다. 이 > 는 내 셸이 /dev/null 을 여는 거라 문제가 없습니다.

여러 명령을 한 번에 root 로 돌려야 하면 sudo sh -c 로 셸째 넘깁니다. 이때 따옴표 안의 변수는 root 셸에서 풀린다는 점만 기억하면 됩니다. 앞 질문처럼 env_reset 으로 사라진 변수는 거기서 빈 값이 됩니다.

# 안 되는 쪽: > 는 내 셸이 연다
sudo echo 'vm.swappiness=10' > /etc/sysctl.d/99-swap.conf
# bash: /etc/sysctl.d/99-swap.conf: Permission denied

# 파일 쓰기를 root 로
echo 'vm.swappiness=10' | sudo tee /etc/sysctl.d/99-swap.conf > /dev/null

# 덧붙이기
echo '127.0.0.1 dev.local' | sudo tee -a /etc/hosts > /dev/null

# 셸째 넘기기
sudo sh -c 'echo 10 > /proc/sys/vm/swappiness'

리다이렉션은 sudo 보다 먼저, 내 권한으로 일어납니다

> 는 sudo 가 아니라 내 셸이 엽니다. 파일 쓰기는 sudo tee 에게 맡깁니다.

sudo cd 로 root 전용 디렉터리에 못 들어가요

sudo cd /var/lib/mysql 은 오류가 나거나, 아무 일도 없이 제자리에 남습니다. cd 는 따로 있는 프로그램이 아니라 셸 안에 든 기능이고, 바꾸는 대상도 그 셸 자신의 작업 디렉터리입니다.

sudo 는 새 프로세스를 띄웁니다. 설령 거기서 디렉터리를 바꾼다 해도 그 프로세스가 끝나면 내 셸은 원래 자리에 그대로 있습니다. sudo 매뉴얼도 sudo cd 는 의미가 없다고 못 박아 둡니다.

그 디렉터리 안에서 뭔가를 하는 게 목적이라면 sudo sh -c 'cd /var/lib/mysql && ls -la' 처럼 셸째 넘기면 됩니다. 명령 하나만 필요하면 cd 없이 sudo ls -la /var/lib/mysql 로 경로를 바로 주는 게 제일 짧습니다.

sudo 1.9.3 부터는 -D 로 작업 디렉터리를 지정할 수 있습니다. 다만 sudoers 에 runcwd 가 허락돼 있어야 하고, 기본 설정에서는 거부됩니다. 여기저기 오래 돌아다닐 일이면 sudo -i 로 root 셸을 여는 게 낫습니다. 그 차이는 바로 다음 질문입니다.

cd 는 셸 자신의 자리를 바꿉니다. sudo 로 띄운 프로세스가 끝나면 아무것도 남지 않습니다.

sudo -s 와 sudo -i 는 뭐가 다른가요?

둘 다 root 셸을 열지만 여는 방식이 다릅니다. -i 는 대상 사용자의 로그인 셸로 뜹니다. .profile 이나 .bash_profile 같은 로그인용 파일을 읽고, 작업 디렉터리를 대상 사용자의 홈으로 옮기고, 로그인했을 때와 비슷한 환경을 만듭니다.

-s 는 셸만 띄웁니다. SHELL 변수가 있으면 그 셸, 없으면 내 계정에 적힌 셸이고, 작업 디렉터리는 지금 자리 그대로입니다. 로그인 파일은 읽지 않습니다.

실무에서 차이가 드러나는 건 HOME 입니다. env_reset 이 켜진 기본 설정에서는 -s 든 그냥 sudo 명령이든 HOME 이 root 의 홈으로 잡힙니다. 그래서 sudo npm install -g 나 sudo pip 가 설정 파일을 /root 쪽에서 찾고, 내 ~/.npmrc 에 적어 둔 사내 레지스트리 주소가 무시됩니다. 설정이 안 먹는다면 명령이 어느 HOME 을 보고 있는지부터 확인합니다.

정리하면, root 로 오래 작업할 땐 -i 로 깔끔한 로그인 환경을, 지금 디렉터리에서 잠깐 root 로 몇 줄 칠 땐 -s 를 씁니다. 어느 쪽이든 끝나면 exit 로 바로 나옵니다. root 셸을 켜 둔 채 다른 일을 하다 보면 내 계정으로 할 작업까지 root 로 하게 됩니다.

cd /srv/app

sudo -s
pwd; echo $HOME        # /srv/app   /root
exit

sudo -i
pwd; echo $HOME        # /root      /root
exit

# 그냥 sudo 명령도 HOME 은 root 기준
sudo sh -c 'echo $HOME'  # /root

-i 는 홈으로 옮겨 가고, -s 는 제자리에 남습니다

-i 는 로그인한 것처럼, -s 는 셸만. HOME 은 둘 다 root 입니다.

조치 후 확인할 것

  • sudo 에서만 command not found 면 sudo -l 로 secure_path 를 보고, 전체 경로로 실행하거나 /usr/local/bin 에 링크한다
  • sudo 안에서 변수가 비면 -E 대신 --preserve-env=이름 으로 골라 넘기고, 늘 필요한 변수는 /etc/sudoers.d/ 에 env_keep 으로 등록한다
  • sudo 로 파일을 쓸 때는 > 대신 sudo tee(덧붙이기는 tee -a)를 쓴다
  • sudo 로 만든 파일이 내 홈에 생겼다면 소유자를 확인하고 chown 으로 되돌린다
  • sudoers 는 반드시 visudo 로 고친다. 문법 오류가 나면 sudo 자체가 막힌다

sudo 는 권한을 올려 주는 명령이라고만 생각하기 쉽지만, 실제로는 명령이 뜰 환경을 새로 짜는 명령이기도 합니다. PATH 는 secure_path 로 바뀌고, 변수는 골라낸 것만 남고, HOME 은 root 로 옮겨 갑니다. 그리고 >, cd 처럼 셸이 하는 일은 sudo 가 손댈 수 없습니다. sudo 를 붙였는데 결과가 이상하면, 무엇이 root 로 돌고 무엇이 여전히 내 셸에서 돌고 있는지부터 나눠 보면 대부분 거기서 풀립니다.

반응형