open atlas
↑ К треку
Командная строка CLI · 04 · 04

Поиск команд с which и type

which, type и command -v находят команды, обыскивая $PATH и собственную таблицу поиска оболочки. type также раскрывает, является ли имя встроенной командой, функцией или псевдонимом — which находит только внешние исполняемые файлы.

CLI Junior ◷ 16 min
Уровень
ОсновыJuniorMiddleSenior

Ты устанавливаешь новую версию Python, запускаешь python3 --version — и он всё равно сообщает старую версию. Почему? Потому что оболочка находит другой python3 раньше в $PATH. Понимание того, как оболочка находит команды — и инструменты, раскрывающие этот поиск — необходимо для отладки проблем окружения, управления несколькими версиями инструментов и написания надёжных скриптов.

К концу урока ты будешь знать, как $PATH управляет поиском команд, и чем which, type и command -v по-разному освещают этот процесс.

Цель

После этого урока ты сможешь объяснить, как оболочка использует $PATH для поиска исполняемых файлов, использовать which для поиска пути внешней команды, использовать type для различия встроенных команд, функций, псевдонимов и внешних команд, и использовать command -v как переносимую альтернативу which в скриптах.

1

$PATH — это список каталогов, разделённых двоеточиями. Когда ты вводишь имя команды без пути, оболочка обыскивает каждый каталог в $PATH слева направо и запускает первое найденное совпадение:

echo $PATH

Типичный вывод:

/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin

Оболочка проверяет /usr/local/bin первым. Если там есть совпадающий исполняемый файл — он используется, всё остальное в списке игнорируется. Именно поэтому pyenv и nvm добавляют свои каталоги-прокладки в начало $PATH: они перехватывают поиск до системного умолчания.

2

which находит путь к внешнему исполняемому файлу. Он обыскивает $PATH по порядку и выводит первое совпадение:

which python3

Вывод:

/usr/bin/python3
which node
/home/alice/.nvm/versions/node/v20.0.0/bin/node

which смотрит только в файловую систему — он не знает о встроенных командах оболочки, функциях или псевдонимах. Если ввести which cd, он выведет пустоту или неверный результат, потому что cd — встроенная команда оболочки и не имеет пути на диске.

3

type раскрывает полную правду об имени. type — встроенная команда bash, которая обращается к собственной таблице поиска оболочки: встроенные команды, функции, псевдонимы, а затем $PATH:

type cd
cd is a shell builtin
type ls
ls is aliased to 'ls --color=auto'
type python3
python3 is /usr/bin/python3
type ll
ll is a function
ll ()
{
    ls -alF
}

Используй type -a имя, чтобы увидеть все совпадения по порядку поиска, а не только первое:

type -a python3
python3 is /usr/local/bin/python3
python3 is /usr/bin/python3

Это раскрывает, что /usr/local/bin/python3 затеняет /usr/bin/python3.

4

command -v — POSIX-переносимая альтернатива для скриптов. which не стандартизирован POSIX и ведёт себя по-разному на разных системах. В скриптах оболочки вместо него используй command -v:

command -v git
/usr/bin/git

В скрипте идиоматичный шаблон для проверки доступности команды:

if ! command -v docker &>/dev/null; then
  echo "docker не установлен" >&2
  exit 1
fi

command -v возвращает код выхода 0, если команда найдена, и ненулевой — иначе. Он также распознаёт встроенные команды и функции. Псевдонимы он не выводит — это намеренно для целей написания скриптов.

5

Просмотр и изменение $PATH. Чтобы добавить каталог в $PATH для текущей сессии:

export PATH="/opt/myapp/bin:$PATH"

Новый каталог добавляется в начало, поэтому ищется первым. Чтобы сделать это постоянным, добавь ту же строку в ~/.bashrc (bash) или ~/.zshrc (zsh).

Чтобы увидеть, откуда загружается команда, и диагностировать конфликты версий:

type -a node          # все исполняемые node в порядке PATH
which -a node         # GNU which -a: то же, только для внешних файлов
Разбор примера

Диагностика неверной версии Python.

После установки Python 3.12 через pyenv команда python3 --version всё равно сообщает 3.10. Расследование:

which python3
/usr/bin/python3

Побеждает системный Python. Проверяем, что pyenv добавил в $PATH:

echo $PATH | tr ':' '\n' | head -5
/home/alice/.pyenv/shims
/home/alice/.pyenv/bin
/usr/local/bin
/usr/bin
/bin

Прокладки pyenv там есть. Но which нашёл /usr/bin/python3 — значит прокладка pyenv для python3 не создана:

type -a python3
python3 is /usr/bin/python3

Только одна запись. Прокладка отсутствует, потому что pyenv нужно указать, какую версию использовать:

pyenv global 3.12.0
type -a python3
python3 is /home/alice/.pyenv/shims/python3
python3 is /usr/bin/python3

Теперь прокладка стоит первой. python3 --version сообщает 3.12.0.

Почему это работает

which на macOS против Linux. На macOS which — это /usr/bin/which и по умолчанию не поддерживает -a (некоторые версии поддерживают, некоторые нет). На Linux с GNU which флаг -a перечисляет все совпадения. В zsh (оболочка macOS по умолчанию) which — встроенная команда, которая показывает псевдонимы и функции — ведя себя как type. Эта непоследовательность — причина, почему command -v предпочтительнее в переносимых скриптах: он определён POSIX, доступен в каждой POSIX-оболочке и ведёт себя согласованно.

Частая ошибка

Использование which для проверки наличия команды в скриптах. which на некоторых системах возвращает 0 даже когда ничего не выводит. Правильная, переносимая идиома:

# НЕВЕРНО — ненадёжно на разных системах
if which mycommand; then

# ВЕРНО
if command -v mycommand &>/dev/null; then

&>/dev/null подавляет и stdout, и stderr, чтобы проверка была тихой. command -v надёжно возвращает ненулевой код, когда команда не найдена.

Проверь себя
Викторина

Ты запускаешь: which cd. Вывод пустой. Почему?

Итог

Оболочка разрешает имя команды по порядку: псевдонимы → функции → встроенные команды → $PATH. which ищет только внешние исполняемые файлы в $PATH и ничего не знает о встроенных командах, функциях или псевдонимах. type (встроенная команда bash) показывает полную картину — к какой категории относится имя и его значение; type -a перечисляет все совпадения по порядку. command -v — POSIX-переносимый эквивалент для скриптов: возвращает 0, если команда найдена (любым способом), и ненулевой код — иначе. Когда команда разрешается в неверную версию, type -a и echo $PATH вместе раскрывают, какой каталог выигрывает поиск.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 4 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.