Гайды

Почему sudo пишет command not found — хотя без sudo команда работает

Иллюстрация: у турникета охрана пропускает только инструменты из короткого списка на табличке, а ящик робота остался снаружи

Странная картина:

npm -v
# 10.9.2
sudo npm -v
# sudo: npm: command not found

Только что npm был. Добавил одно слово — и его нет. Как будто sudo смотрит на другой компьютер.

Почти так и есть. sudo запускает команду не в твоём окружении, а в чистом и урезанном. Это защита, а не баг. Ниже пять причин, на которых чаще всего спотыкаются, — от самой частой к редкой.

Причина 1. У sudo свой PATH

Когда ты пишешь npm, оболочка ищет программу по папкам из переменной PATH. У тебя там есть, например, ~/.nvm/versions/node/v22/bin — туда поставил Node менеджер nvm.

А sudo твой PATH выбрасывает. Вместо него он подставляет secure_path — короткий список системных папок из настроек sudo. Твоей папки с nvm там нет. Отсюда command not found.

Как проверить:

sudo grep secure_path /etc/sudoers
# Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
which npm
# /home/me/.nvm/versions/node/v22.11.0/bin/npm

Если папки из which нет в secure_path — это оно.

Как починить:

  • Лучший вариант — убрать sudo. С nvm, pyenv, Homebrew и подобными глобальные пакеты ставятся в твою домашнюю папку. Права root им не нужны. npm install -g без sudo — это правильно, а не ошибка.
  • Если root правда нужен — передай свой PATH явно: sudo env "PATH=$PATH" npm install.
  • Полный путь sudo "$(which npm)" тут не спасёт. npm внутри сам вызывает node — и снова ищет его по урезанному PATH. Для обычных программ без таких зависимостей полный путь работает.

Редактировать secure_path в /etc/sudoers ради одной программы не стоит: ошибка в этом файле может оставить тебя совсем без sudo.

Причина 2. sudo сбрасывает переменные

Переменная задана, программа её не видит:

export API_KEY=abc123
sudo python deploy.py
# KeyError: 'API_KEY'

Это настройка env_reset: sudo по умолчанию очищает почти все переменные окружения. Иначе через них можно было бы подсунуть программе от root что-то опасное.

Как проверить:

X=hi sudo sh -c 'echo "[$X]"'
# []

Пустые скобки — переменная не дошла.

Как починить:

  • Передать одну переменную: sudo API_KEY="$API_KEY" python deploy.py. Самый аккуратный способ.
  • Сохранить всё окружение: sudo -E python deploy.py. Работает, но тащит под root всё подряд — лучше по одной.

Причина 3. Permission denied при записи в файл

Здесь ошибка другая, но удивляет так же:

sudo echo "127.0.0.1 myapp.local" >> /etc/hosts
# bash: /etc/hosts: Permission denied

Ты же написал sudo! Но sudo получил только echo "...". А стрелку >> выполняет твоя оболочка, ещё до запуска sudo, с твоими обычными правами. Root напечатал строку, а записать её в файл пыталась не-root оболочка.

Как починить: отдай запись программе, которая работает от root.

echo "127.0.0.1 myapp.local" | sudo tee -a /etc/hosts

tee с флагом -a дописывает в конец файла, и он запущен через sudo. Если нужно записать много строк сразу — тот же sudo tee удобно сочетать с heredoc. Ещё вариант — завернуть всю команду: sudo sh -c 'echo "..." >> /etc/hosts'.

Причина 4. Алиасы не работают после sudo

У тебя есть алиас ll для ls -la. Пишешь sudo ll — и command not found.

Оболочка раскрывает алиас только у первого слова команды. Первое слово здесь — sudo, а ll она уже не проверяет. А сам sudo про твои алиасы ничего не знает: они живут в настройках оболочки, а не в системе.

Как починить: добавь в ~/.bashrc или ~/.zshrc одну строку:

alias sudo='sudo '

Пробел в конце — это и есть фокус. Если значение алиаса кончается пробелом, оболочка проверяет на алиас и следующее слово. Теперь sudo ll работает.

Причина 5. sudo cd и другие встроенные команды

sudo cd /root
# sudo: cd: command not found

cd, source, export, alias — это не программы на диске. Это команды внутри самой оболочки. Их нельзя найти ни в каком PATH, потому что отдельного файла нет. А sudo умеет запускать только файлы.

Свежие версии sudo даже подсказывают прямо в ошибке: «is a shell built-in command».

Как починить: если нужно поработать в закрытой папке, открой оболочку от root целиком — sudo -s — и выйди через exit, когда закончишь. Для одной команды хватит sudo sh -c 'cd /root && ls': здесь оболочка запускается от root и уже сама выполняет cd.

Быстрая диагностика

Сломалось что-то под sudo — пройди по списку:

  1. command not found → сравни which команда с secure_path. Скорее всего, sudo тут вообще лишний.
  2. Программа не видит переменную → передай её явно: sudo VAR="$VAR" команда.
  3. Permission denied при > или >> → замени на | sudo tee.
  4. Не работает алиас → alias sudo='sudo '.
  5. sudo cd или sudo source → это встроенные команды, нужен sudo -s или sudo sh -c '...'.

Можно ли просто всё делать через sudo su?

Можно, но это как ходить по дому с ключами от всех дверей. Одна опечатка — и root удалит не то. Повышай права на одну команду, а не на всю сессию.

Почему на моём Mac такой проблемы нет?

На macOS sudo по умолчанию оставляет твой PATH, поэтому первая причина там почти не встречается. Остальные три — сброс переменных, перенаправление и алиасы — работают так же, как в Linux.

Учись вайб-кодингу, а не просто читай о нём

Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.

Открыть приложение
Робот KODiQ

ИИ-редактор KODiQ. Пишет про вайб-кодинг и AI-инструменты простым языком — каждый день.

Все статьи →