// заметки
Linux: «команда не найдена» — PATH, ifconfig, pip
command not found в Linux: как найти бинарь по PATH, почему sudo и login shell видят другой путь и что поставить вместо ifconfig и pip — разбор с командами
bash: ifconfig: команда не найдена и bash: pip: команда не найдена выглядят как одна поломка, но причины разные: в первом случае бинарника нет в системе, во втором он установлен, а каталога с ним нет в PATH. Ниже разбор механизма поиска команд в PATH и командный ряд type -a, command -v, echo $PATH, hash -r, который за минуту показывает, что именно чинить
Симптом
Ошибка появляется, когда shell не нашёл команду ни в одном каталоге из PATH. Текст зависит от оболочки и локали, смысл один
$ ifconfig
bash: ifconfig: команда не найдена
$ pip --version
bash: pip: команда не найдена
$ iptables -L
bash: iptables: команда не найденаiptables здесь пример команды из /usr/sbin: под sudo она может запуститься, а под обычным пользователем нет. Похожая внешне ошибка встречается при настройке базы: PostgreSQL: connection refused и установка PostgreSQL
Диагностика
Первым делом спрашиваем shell, где он ищет команду. command -v печатает путь и возвращает код 0, если команда найдена, и молчит с кодом 1, если нет
$ command -v ip
/usr/bin/ip
$ command -v ifconfig
$ echo $?
1type -a показывает все совпадения: алиасы, функции, встроенные команды и бинарники, в порядке выбора
$ type -a python3
python3 is /usr/bin/python3
$ type -a echo
echo is a shell builtin
echo is /usr/bin/echoДальше смотрим сам PATH: это каталоги через двоеточие, поиск идёт слева направо
$ echo $PATH
/home/$USER/.local/bin:/usr/local/bin:/usr/bin:/bin
$ echo $PATH | tr ':' '\n'
/home/$USER/.local/bin
/usr/local/bin
/usr/bin
/binЕсли каталога в списке нет, установка сама по себе команду не покажет. Проверяем, лежит ли бинарник на диске
$ ls -l /usr/sbin/ifconfig 2>&1
ls: cannot access '/usr/sbin/ifconfig': No such file or directoryФайла нет — виноват пакет. Файл есть, а команда не находится — виноват PATH. Отдельный источник путаницы: bash кеширует найденные пути в хеш-таблице, и свежеустановленная команда иногда не видна до hash -r
Причина
PATH — переменная окружения, которую читают shell и многие программы. Первое совпадение выигрывает, поэтому порядок каталогов важен. Если каталога в списке нет, для shell команды не существует, даже когда файл лежит на диске
Каталоги /sbin и /usr/sbin на многих системах добавляются в PATH только для root. Обычный пользователь их не видит, поэтому iptables или visudo дают «команда не найдена», а sudo iptables работает
sudo по умолчанию сбрасывает окружение через env_reset и подставляет свой PATH из директивы secure_path в /etc/sudoers, где /usr/sbin обычно есть
$ sudo env | grep '^PATH='
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/binВторой источник расхождений — тип shell. Login shell (вход по SSH, su -, bash --login) читает /etc/profile и ~/.bash_profile или ~/.profile. Non-login интерактивный shell (терминал в графической сессии, bash без флагов) читает ~/.bashrc. PATH, дописанный только в один файл, во втором режиме не появится
Третья причина — кеш команд. Bash запоминает путь к найденному бинарнику и не перечитывает PATH, поэтому только что установленная команда не находится до hash -r или нового сеанса
python3 -m pip надёжнее, чем pip: Python в системе может быть несколько, и pip без версии указывает не на тот. Каталог ~/.local/bin, куда pip кладёт пользовательские скрипты, по умолчанию тоже не в PATH
Решение
Разбор даёт два сценария. Пакет не установлен — ставим пакет. Команда есть, а каталога нет в PATH — добавляем каталог
Сценарий 1: ifconfig. В Debian и Ubuntu он живёт в net-tools, который по умолчанию не ставится. Замена — ip из iproute2
$ ip -brief address
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.0.2.10/24Если нужен именно привычный ifconfig, например для старого скрипта:
$ sudo apt update
$ sudo apt install net-tools
$ sudo /usr/sbin/ifconfig -aПолный путь обходит проблему с PATH на время: каталог /usr/sbin под sudo доступен через secure_path. Ставить net-tools только ради ручной проверки не стоит, у ip шире возможности и он уже установлен
Сценарий 2: pip. В Debian и Ubuntu пакет называется python3-pip и даёт pip3. Запускать лучше через python3 -m pip, чтобы не перепутать интерпретатор
$ sudo apt update
$ sudo apt install python3-pip
$ python3 -m pip --version
pip <version> from .../dist-packages/pip (python 3.x)В Fedora и RHEL пакет называется python3-pip, в Arch — python-pip, утилита ip входит в iproute2. Имена пакетов проверяйте командой менеджера пакетов своей системы
Сценарий 3: ~/.local/bin. Сюда попадают скрипты из pip install --user и самодостаточные утилиты. Каталог часто не в PATH — добавляем его в ~/.profile для login shell и в ~/.bashrc для интерактивного
# ~/.profile и ~/.bashrc
export PATH="$HOME/.local/bin:$PATH"Применяем без перелогина и сбрасываем кеш:
$ . ~/.bashrc
$ hash -r
$ command -v <tool>
/home/$USER/.local/bin/<tool>hash -r затрагивает только текущий сеанс: в новом терминале кеш пуст. Когда команда нужна всем пользователям, каталог добавляют в системный профиль через /etc/profile.d/*.sh, но это задача администратора. Если сообщение ограничено фразой «команда не найдена», в Ubuntu помогает пакет command-not-found: он подсказывает имя пакета с командой
Проверка
Проверяем тремя командами: где команда, что в PATH, отвечает ли бинарник
$ command -v ifconfig || echo "нет в PATH"
нет в PATH
$ command -v pip3 || echo "нет в PATH"
/usr/bin/pip3
$ ip -brief address
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 192.0.2.10/24Для ifconfig вывод пуст: бинарник из net-tools лежит в /usr/sbin, которого нет в PATH обычного пользователя, поэтому срабатывает ветка || echo. Полный путь из «Решения» обходит это: sudo /usr/sbin/ifconfig -a
Порядок и дубли в PATH удобно смотреть построчно
$ echo $PATH | tr ':' '\n' | nl
1 /home/$USER/.local/bin
2 /usr/local/bin
3 /usr/bin
4 /binЕсли command -v печатает путь и возвращает 0, команда запустится в этом shell
$ command -v python3 >/dev/null && echo ok
okПодводные камни
- `hash -r` помогает только в текущем shell. Новый терминал читает
PATHзаново, поэтому там правка из~/.bashrcуже действует - `PATH` из `~/.bashrc` не виден неинтерактивным сессиям.
ssh host command, cron и сервисы systemd не читают интерактивный профиль: им нужен~/.profile, директиваEnvironment=в unit-файле или полный путь к программе - `sudo` не наследует пользовательский `PATH`.
sudo -Eсработает только при разрешённомSETENVвsudoers; иначе используйтеsudo env "PATH=$PATH" <command>или полный путь - Порядок в `PATH` решает. Если поставить
$HOME/.local/binперед/usr/bin, одноимённая пользовательская команда перекроет системную — иногда это ровно то, что нужно, иногда источник загадочных сбоев - Системный Python в Debian и Ubuntu помечен как externally managed.
pip installбез флага падает с ошибкой проexternally-managed-environment; для пользовательских пакетов нуженvenvилиpipx, а неsudo pip - Не тащите `net-tools` вслепую. Старые скрипты на
ifconfigиnetstatпродолжат работать, но новые вызовы стоит переводить наipиssизiproute2
Итог
«Команда не найдена» — это один из двух случаев: бинарника нет или его каталога нет в PATH. command -v и type -a показывают первое, echo $PATH — второе, hash -r сбрасывает кеш после установки. Разница между login и non-login shell объясняет, почему команда работает в одном терминале и пропадает в другом или под sudo
Если серверов много и такие разборы повторяются, посмотрите администрирование серверов. Когда проблема в окружении приложения, а не в оболочке, поможет разработка бэкенда
Похожие заметки
pkill -f убивает сам себя: шаблон совпадает с командой
pkill -f и pgrep -f сопоставляют шаблон со всей командной строкой, включая обёртку bash -c. Разбираю, почему команда убивает себя, и какие фильтры помогают
Nix на CachyOS: установка невозможна — rootless-запуск
Nix не ставится, если корень read-only, sudo сломан, а путь /nix зашит в ELF. Разбор трёх ограничений и rootless-запуск через mount-namespace и chroot
Firefox: профиль слетел из-за profile-sync-daemon
После перезапуска Firefox пропали расширения, хотя закладки синхронизировались. Разбор: как psd увёл профиль в пустой fuse-overlayfs, и как вернуть его с диска