Сегодня я обсуждала с другом, как добавить каталог в переменную окружения PATH. Мне это кажется очевидным, потому что я давно пользуюсь терминалом, но когда я пошла искать инструкцию, внезапно не нашла такой, которая бы объясняла все шаги. Во многих просто написано «добавьте это в ~/.bashrc», но что, если я не использую bash? Что, если конфигурация bash у меня вообще в другом файле? И как понять, какой именно каталог нужно добавить?

Поэтому я решила записать разбор шагов и упомянуть несколько подводных камней, на которые я натыкалась за эти годы.

Содержание:

Шаг 1: какую оболочку shell вы используете?

Если вы не уверены, какой shell у вас используется, это можно выяснить. Выполните команду:

ps -p $$ -o pid,comm=

  • если вы используете bash, она выведет что-то вроде 97295 bash

  • если вы используете zsh, она выведет что-то вроде 97295 zsh

  • если вы используете fish, она выдаст ошибку вроде «In fish, please use $fish_pid» (синтаксис $$ в fish недопустим, но в любом случае по сообщению об ошибке понятно, что вы используете fish, что вы, скорее всего, и так знали)

Во многих дистрибутивах Linux интерактивная оболочка по умолчанию — bash (хотя это зависит от дистрибутива и настроек пользователя), а zsh — оболочка по умолчанию в macOS (для интерактивных сессий Terminal). В этой инструкции я буду рассматривать только bash, zsh и fish.

Шаг 2: найдите файл конфигурации вашего shell

  • в zsh это, скорее всего, ~/.zshrc

  • в bash это может быть ~/.bashrc, но всё сложнее, см. примечание в следующем разделе

  • в fish это, скорее всего, ~/.config/fish/config.fish (если хотите быть уверены на 100%, можно выполнить echo $__fish_config_dir)

Примечание о файле конфигурации bash

У Bash несколько «стартовых» файлов. Для интерактивной не-login сессии обычно читается ~/.bashrc. Для login-сессии Bash читает /etc/profile, а затем первый доступный из ~/.bash_profile, ~/.bash_login, ~/.profile (в таком порядке).

Если вы не уверены, какой файл читает ваш Bash, рекомендую проверить это так:

  1. Добавьте echo hi there в ~/.bashrc

  2. Перезапустите терминал

  3. Если вы видите «hi there», значит используется ~/.bashrc! Ура!

  4. Иначе удалите эту строку и попробуйте то же самое с ~/.bash_profile

  5. Если первые два варианта не сработали, можно попробовать и ~/.profile.

(В интернете есть куча подробных блок-схем, которые объясняют, как Bash выбирает, какой конфиг читать, но на мой взгляд, нет смысла держать это в голове. Самый быстрый способ точно узнать — просто проверить).

Шаг 3: выясните, какой каталог нужно добавить

Допустим, вы пытаетесь установить и запустить программу под названием http-server, но она не работает, например так:

$ npm install -g http-server
$ http-server
bash: http-server: command not found

Как узнать, в каком каталоге находится http-server? Честно говоря, в общем случае это не так уж просто. Часто ответ звучит примерно так: «зависит от того, как у вас настроен npm». Несколько идей:

  • Часто при настройке нового установщика (cargo, npm, homebrew и т. п.) он при первом запуске выводит инструкции о том, как обновить PATH. Если внимательно смотреть, можно поймать подсказку прямо там.

  • Иногда установщики сами автоматически правят конфигурацию вашего shell и обновляют PATH за вас.

  • Иногда достаточно просто загуглить «куда npm устанавливает пакеты?» и найти ответ.

  • У некоторых инструментов есть команда, которая показывает, куда они настроены устанавливать файлы, например:

    • Node/npm: npm config get prefix (затем добавьте /bin/)

    • Go: go env GOBIN (если пусто — используйте go env GOPATH и добавьте /bin/)

    • asdf: добавьте каталог shims в PATH (и при необходимости учитывайте ASDF_DATA_DIR): export PATH="${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH"

Шаг 3.1: перепроверьте, что это правильный каталог

Когда вы нашли каталог, который, как вам кажется, подходит, обязательно убедитесь, что это действительно он. Например, я выяснила, что на моей машине http-server находится в ~/.npm-global/bin. Проверить это можно, попробовав запустить http-server напрямую из этого каталога, вот так:

$ ~/.npm-global/bin/http-server
Starting up http-server, serving ./public

Сработало! Теперь, когда вы точно знаете, какой каталог нужно добавить в PATH, переходим к следующему шагу.

Шаг 4: отредактируйте конфигурацию shell

Теперь у нас есть две ключевые вещи:

  • Какой каталог вы хотите добавить в PATH (например, ~/.npm-global/bin/)

  • Где находится файл конфигурации вашего shell (например, ~/.bashrc, ~/.zshrc или ~/.config/fish/config.fish)

Дальнейшие действия зависят от того, какой shell вы используете.

инструкция для bash:

Откройте файл конфигурации вашего shell и добавьте строку вида:

export PATH=$PATH:~/.npm-global/bin/

(разумеется, замените ~/.npm-global/bin на реальный каталог, который вы хотите добавить)

инструкция для zsh:

Можно сделать то же самое, что и в bash, но в zsh есть и более «изящный» синтаксис, если вы предпочитаете его:

path=(
  $path
  ~/.npm-global/bin
)

инструкция для fish:

В fish синтаксис отличается:

set -Ux PATH ~/.npm-global/bin $PATH

(в fish также можно использовать fish_add_path, об этом будет сказано ниже)

Шаг 5: перезапустите shell

Очень важный шаг: изменения в конфигурации shell не вступят в силу, если вы его не перезапустите.

Есть два способа:

  1. Открыть новый терминал (или новую вкладку терминала), возможно закрыв старый, чтобы не запутаться.

  2. Можно выполнить exec "$SHELL" для перезапуска текущей оболочки, либо просто открыть новую сессию терминала. Если вам нужна login-сессия, используйте bash -l или zsh -l.

По моему опыту, оба способа обычно работают нормально.

На этом всё должно быть готово! Попробуйте снова запустить программу, которую вы пытались запустить ранее, и, надеюсь, теперь всё сработает.

Для тех, кто хочет быстро подтянуть основы, рекомендуем мини-видеокурс «Linux для начинающих», сейчас всего за 10 рублей.

Если нет, вот несколько проблем, с которыми вы можете столкнуться.

Проблема 1: запускается не та программа

Если запускается не та версия программы, возможно, нужно добавить каталог в начало PATH, а не в конец.

Например, на моей системе установлены две версии python3, что можно увидеть, выполнив which -a:

$ which -a python3
/usr/bin/python3
/opt/homebrew/bin/python3

Shell использует первую из перечисленных версий.

Если вы хотите использовать версию из Homebrew, нужно добавить соответствующий каталог (/opt/homebrew/bin) в начало PATH. Для этого в файле конфигурации shell укажите не стандартный вариант $PATH:/opt/homebrew/bin/, а наоборот — /opt/homebrew/bin/:$PATH:

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

или в fish:

set -gx PATH /opt/homebrew/bin $PATH

Проблема 2: программа запускается не из вашего shell

Все приведённые выше инструкции работают только в том случае, если вы запускаете программу из shell. Если программа запускается из IDE, из графического интерфейса, в задании cron или иным способом, каталог в PATH нужно добавлять иначе, и конкретные шаги будут зависеть от ситуации.

в задании cron

Возможные варианты:

  • Использовать полный путь к программе, например /home/bork/bin/my-program

  • Задать переменные окружения в crontab отдельными строками перед заданиями (например, PATH=/bin:/usr/bin:/usr/local/bin:…). Полное значение PATH, которое используется в вашем shell, можно получить командой echo "PATH=$PATH".

Честно говоря, я не уверена, как лучше решать это для IDE или графических приложений, поскольку давно с таким не сталкивался. Добавлю инструкции, если кто-то подскажет корректный способ.

Проблема 3: дубли в PATH мешают отладке

Если вы редактируете PATH и запускаете новый shell командой bash (или zsh, или fish), часто в PATH появляются дубликаты, потому что ваш конфиг оболочки (или подключаемые скрипты инициализации) при каждом запуске снова добавляют одни и те же каталоги в PATH.

Лично я не встречала ситуаций, когда такие дубли ломают что-то, но они могут мешать разбираться, что происходит с PATH, если вы пытаетесь понять его содержимое.

Вот несколько способов с этим справиться:

  1. Если вы отлаживаете PATH, делайте это в новом окне терминала, чтобы получить «чистое» состояние. Так обычно удаётся избежать дублей.

  2. Удалять дубли из PATH в конце конфигурации shell (в zsh можно удалить дубли в PATH через уникализацию массива path: typeset -U path).

  3. При добавлении каталога проверять, что его ещё нет в PATH (например, в fish это можно сделать через fish_add_path /some/directory).

Способ удаления дублей зависит от конкретного shell, и встроенный механизм есть не всегда, поэтому придётся отдельно смотреть, как это делается именно у вас.

Проблема 4: после обновления PATH пропадает история команд

Вот ситуация, в которую легко попасть в bash или zsh:

  1. Выполнить команду (она упала с ошибкой)

  2. Обновить PATH

  3. Запустить bash, чтобы перечитать конфигурацию

  4. Нажать стрелку вверх пару раз, чтобы повторить команду (или открыть новый терминал)

  5. А команды в истории нет! Почему?

Так происходит потому, что в bash история записывается в файл при выходе и читается при запуске новой сессии, поэтому вложенный shell не видит последние команды.

Несколько вариантов, как это исправить:

  • Вместо того чтобы запускать bash для перечитывания конфигурации, выполните source ~/.bashrc (или source ~/.zshrc для zsh). Это перечитает конфиг в текущей сессии.

  • Настройте shell так, чтобы история сохранялась постоянно, а не только при выходе. (Как именно это сделать, зависит от того, используете ли вы bash или zsh. Опции истории в zsh довольно запутанные, и я не уверен, какой вариант там оптимальный).

Примечание о source

Когда вы впервые устанавливаете cargo (установщик Rust), он предлагает такие инструкции по настройке PATH, где вообще не указывается конкретный каталог.

Обычно предлагается выполнить одну из следующих команд 
(обратите внимание на точку в начале строки):

. "$HOME/.cargo/env" 	# Для sh/bash/zsh/ash/dash/pdksh
 source "$HOME/.cargo/env.fish" # Для fish

Идея в том, что вы добавляете эту строку в конфигурацию своего shell, а скрипт автоматически настраивает PATH (и, возможно, что-то ещё) за вас.

Это довольно распространённый подход (например, Homebrew рекомендует выполнить eval "$(/opt/homebrew/bin/brew shellenv)), и тут есть два варианта действий:

  1. Просто сделать то, что предлагает инструмент (например, добавить . "$HOME/.cargo/env" в конфигурацию shell).

  2. Разобраться, какие именно каталоги этот скрипт добавляет в PATH, и прописать их вручную. Вот как бы я это сделала:

  • Выполнить . "$HOME/.cargo/env" в своём shell (или версию для fish, если используете fish).

  • Выполнить echo "$PATH" | tr ':' '\n' | grep cargo, чтобы понять, какие каталоги были добавлены.

  • Увидеть, что там указан /Users/bork/.cargo/bin, и сократить его до ~/.cargo/bin.

  • Добавить каталог ~/.cargo/bin в PATH (по инструкции из этого поста).

Я не думаю, что следовать рекомендациям инструмента неправильно (возможно, это даже «правильный» способ), но лично я обычно выбираю второй вариант, потому что предпочитаю точно понимать, какие изменения в конфигурации вношу.

Примечание о fish_add_path

В fish есть удобная функция fish_add_path, которую можно использовать для добавления каталога в PATH вот так:

fish_add_path /some/directory

Это здорово — команда действительно очень простая — но я перестал её использовать по нескольким причинам.

  1. Иногда fish_add_path обновляет PATH для всех будущих сессий (через «универсальную переменную» — universal variable), а иногда только для текущей, и мне сложно предсказать, какой вариант будет применён. В теории документация это объясняет, но я не смог в ней до конца разобраться.

  2. Если через несколько недель или месяцев вам понадобится удалить этот каталог из PATH (например, вы ошиблись), сделать это оказывается не так просто. В комментариях к одному из обсуждений на GitHub есть инструкции, но всё равно это не самый очевидный процесс.

Вот и всё.

Надеюсь, это кому-то поможет. Если при добавлении каталога в PATH вы сталкивались с другими подводными камнями, расскажите в комментариях.

Если хочется разбираться в таких вещах глубже — от того, как формируется окружение shell, до настройки сервисов и сетевых правил, — обратите внимание на курс «Administrator Linux. Basic». На курсе системно разбирают базу Linux, работу в Bash и администрирование серверов, чтобы уверенно чувствовать себя в инфраструктуре.

Для знакомства с форматом обучения и экспертами приходите на бесплатные демо-уроки:

  • 26 февраля, 20:00. «С Windows на Linux: первый шаг системного администратора». Записаться

  • 12 марта, 20:00. «Перенаправление потоков в Linux». Записаться

  • 23 марта, 19:00. «SSH: безопасный доступ и автоматизация в Linux». Записаться