Как правильно добавить путь к PATH?

922

Мне интересно, где новый путь должен быть добавлен к PATHпеременной среды. Я знаю, что это может быть достигнуто путем редактирования .bashrc(например), но не ясно, как это сделать.

Сюда:

export PATH=~/opt/bin:$PATH

или это?

export PATH=$PATH:~/opt/bin
Paolo
источник
printf '\ nPATH = $ PATH: "путь для добавления" \ nexport PATH \ n' >> ~ / .bashrc
Sudoer
Если некоторые пути уже добавлены, например PATH=$PATH:$HOME/.local/bin:$HOME/bin, можно добавить другой путь, разделив его: например PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/ec2-user/pear/bin.
Сандипан Нат
2
Эти ответы работают на все вкусы Linux?
Ungeheuer

Ответы:

1032

Простые вещи

PATH=$PATH:~/opt/bin

или же

PATH=~/opt/bin:$PATH

в зависимости от того, хотите ли вы добавить ~/opt/binв конце (для поиска после всех других каталогов, если есть программа с одинаковым именем в нескольких каталогах) или в начале (для поиска перед всеми другими каталогами).

Вы можете добавить несколько записей одновременно. PATH=$PATH:~/opt/bin:~/opt/node/binили вариации на заказ работают просто отлично. Не ставьте exportв начале строки, так как это связано с дополнительными сложностями (см. Ниже «Примечания к оболочкам, кроме bash»).

Если ваша система PATHсоздается из множества различных компонентов, вы можете получить дублирующиеся записи. См. Как добавить путь к домашней директории, который будет обнаружен Unix, какой командой? и удалите дубликаты записей $ PATH с помощью команды awk, чтобы избежать добавления дубликатов или их удаления.

~/binКстати, некоторые дистрибутивы автоматически помещают в ваш PATH, если он существует.

Где его поставить

Поместите линию , чтобы изменить PATHв ~/.profile, или , ~/.bash_profileесли это то, что у вас есть.

Обратите внимание, что ~/.bash_rcне читается ни одной программой, и ~/.bashrcявляется файлом конфигурации интерактивных экземпляров bash. Вы не должны определять переменные среды в ~/.bashrc. Правильное место для определения переменных среды, таких как PATHis ~/.profile(или ~/.bash_profileесли вас не волнуют другие оболочки, кроме bash). Посмотрите, в чем разница между ними и какой я должен использовать?

Не помещайте это в /etc/environmentили ~/.pam_environment: это не файлы оболочки, вы не можете использовать подстановки, как $PATHтам. В этих файлах вы можете только переопределить переменную, но не добавлять к ней.

Потенциальные осложнения в некоторых системных скриптах

Вам не нужно, exportесли переменная уже находится в среде: любое изменение значения переменной отражается в среде. PATH¹ в значительной степени всегда в среде; все системы Unix устанавливают его очень рано (обычно в самом первом процессе).

Во время входа в систему вы можете полагаться на то, PATHчто уже находитесь в среде и уже содержат некоторые системные каталоги. Если вы пишете сценарий , который может быть выполнен в начале при установке какой - то виртуальной среде, необходимо убедиться , что PATHне является пустым и экспортируется: если PATHдо сих пор не установлено, то что - то вроде PATH=$PATH:/some/directoryбы установлен PATHна :/some/directory, а пустой компонент в начале означает текущий каталог (как .:/some/directory).

if [ -z "${PATH-}" ]; then export PATH=/usr/local/bin:/usr/bin:/bin; fi

Примечания о снарядах, кроме Баш

В bash, ksh и zsh, exportесть специальный синтаксис, и то и другое PATH=~/opt/bin:$PATHи export PATH=~/opt/bin:$PATHделают правильные вещи даже. В других оболочках в стиле Bourne / POSIX, таких как dash (который есть /bin/shво многих системах), exportанализируется как обычная команда, что подразумевает два различия:

Таким образом, в таких оболочках, как dash, export PATH=~/opt/bin:$PATHустанавливается PATHлитеральная строка, ~/opt/bin/:за которой следует значение PATHдо первого пробела. PATH=~/opt/bin:$PATH(голое задание) не требует кавычек и делает правильные вещи. Если вы хотите использовать exportв переносимом скрипте, вам нужно написать export PATH="$HOME/opt/bin:$PATH"или PATH=~/opt/bin:$PATH; export PATH(или PATH=$HOME/opt/bin:$PATH; export PATHдля переносимости даже в оболочку Bourne, которая не принимала export var=valueи не выполняла расширение тильды).

¹ Это было не так в оболочках Bourne (как в реальной оболочке Bourne, а не в современных оболочках в стиле POSIX), но в наши дни вы вряд ли встретите такие старые оболочки.

жилль
источник
До сих пор не в состоянии понять сложности с экспортом. не могли бы вы упростить это?
Прийоет Приём
@priojeetpriyom Простое объяснение: вам не нужно export.
Жиль
Спасибо за этот ответ, очень подробно. Вы говорите: « Вы не должны определять переменные среды в ~ / .bashrc », но, к сожалению, 100% программ, которые я установил в моей системе и которые изменяют путь (FZF и Rust's Cargo), изменяют путь в нем .bashrc. Я предполагаю, что, поскольку FZF написан на Rust, он также следует шаблону Rust.
icc97
83

В любом случае работает, но они не делают то же самое: элементы PATHпроверяются слева направо. В вашем первом примере исполняемые файлы in ~/opt/binбудут иметь приоритет над установленными, например in /usr/bin, которые могут быть, а могут и не быть теми , которые вы хотите.

В частности, с точки зрения безопасности, опасно добавлять пути вперед, потому что, если кто-то может получить доступ для записи к вашему ~/opt/bin, он может добавить, например, другое ls, которое вы, вероятно, вместо этого могли бы использовать вместо этого. из того /bin/lsне замечая. Теперь представьте то же самое для sshили вашего браузера или выбора ... (То же самое происходит трижды для вставки на вашем пути.)

Ульрих Шварц
источник
6
Но если вы хотите иметь свою собственную, настроенную версию ls, вы должны поместить ее в каталог заранее /bin.
Бармар
16
или псевдоним ls = myls
waltinator
37

Я смущен вопросом 2 (так как удален из вопроса, так как это было связано с не связанной проблемой):

Как можно добавить больше путей в разные строки? Первоначально я думал, что это может сделать свое дело:

export PATH=$PATH:~/opt/bin
export PATH=$PATH:~/opt/node/bin

но это не так, потому что второе назначение не только добавляет ~/opt/node/bin, но и все PATHранее назначенное.

Это возможный обходной путь:

export PATH=$PATH:~/opt/bin:~/opt/node/bin

но для удобства чтения я предпочел бы иметь одно назначение для одного пути.

Если вы говорите

PATH=~/opt/bin

это все, что будет в вашем ПУТИ. PATH - это просто переменная окружения, и если вы хотите добавить ее в PATH, вам нужно перестроить переменную с тем содержимым, которое вы хотите. То есть то, что вы приводите в качестве примера к вопросу 2, это именно то, что вы хотите сделать, если только я полностью не упускаю суть вопроса.

Я использую обе формы в моем коде. У меня есть общий профиль, который я устанавливаю на каждой машине, на которой я работаю, который выглядит так, чтобы приспособиться к потенциально отсутствующим каталогам:

export PATH=/opt/bin:/usr/local/bin:/usr/contrib/bin:/bin:/usr/bin:/usr/sbin:/usr/bin/X11
# add optional items to the path
for bindir in $HOME/local/bin $HOME/bin; do
    if [ -d $bindir ]; then
        PATH=$PATH:${bindir}
    fi
done
Карл Крейвенс
источник
2
Вы правы насчет примера вопроса 2, он работает. Другая проблема, связанная с PATH в моей системе, смутила меня. Простите за это.
Паоло
26

Пуленепробиваемый способ добавления / предоплаты

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

Важным моментом является то, что, даже если системные скрипты не используют это (интересно, почему) * 1 , пуленепробиваемый способ добавить путь (например, $HOME/bin) в переменную среды PATH - это

PATH="${PATH:+${PATH}:}$HOME/bin"

для добавления (вместо PATH="$PATH:$HOME/bin") и

PATH="$HOME/bin${PATH:+:${PATH}}"

за предлог (вместо PATH="$HOME/bin:$PATH")

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

Пояснение (из расширения параметров оболочки ):

${parameter:+word}

Если parameterравно null или не установлено, ничто не подставляется, в противном случае подставляется расширение word.

Таким образом, ${PATH:+${PATH}:}расширяется до: 1) ничего, если PATHноль или не установлен, 2) ${PATH}:, если PATHустановлено.

Примечание : это для bash.


* 1 Я только что обнаружил, что подобные сценарии devtoolset-6/enableдействительно используют это,

$ cat /opt/rh/devtoolset-6/enable
# General environment variables
export PATH=/opt/rh/devtoolset-6/root/usr/bin${PATH:+:${PATH}}
...
sancho.s
источник
24

Linux определяет путь поиска исполняемого файла с помощью $PATHпеременной среды. Чтобы добавить каталог / data / myscripts в начало $PATHпеременной среды, используйте следующее:

PATH=/data/myscripts:$PATH

Чтобы добавить этот каталог в конец пути, используйте следующую команду:

PATH=$PATH:/data/myscripts

Но предыдущего недостаточно, потому что когда вы устанавливаете переменную среды внутри скрипта, это изменение вступает в силу только внутри скрипта. Есть только два способа обойти это ограничение:

  • Если в сценарии вы экспортируете переменную окружения, она действует в любых программах, вызываемых сценарием. Обратите внимание, что это не эффективно в программе, которая вызывает скрипт.
  • Если программа, вызывающая скрипт, делает это путем включения вместо вызова, любые изменения среды в скрипте вступают в силу в вызывающей программе. Такое включение может быть сделано с помощью команды точка или команды источника.

Примеры:

$HOME/myscript.sh
source $HOME/myscript.sh

Включение в основном включает «вызываемый» сценарий в «вызывающий» сценарий. Это как #include в C. Так что это эффективно внутри "вызывающего" скрипта или программы. Но, конечно, это не эффективно ни в каких программах или скриптах, вызываемых вызывающей программой. Чтобы сделать его эффективным на протяжении всей цепочки вызовов, вы должны следовать настройке переменной среды с помощью команды экспорта.

Например, программа оболочки bash включает содержимое файла .bash_profile путем включения. Поместите следующие 2 строки в .bash_profile:

PATH=$PATH:/data/myscripts
export PATH

эффективно помещает эти 2 строки кода в программу bash. Таким образом, в bash переменная $ PATH включает $HOME/myscript.shи из-за оператора экспорта все программы, вызываемые bash, имеют измененную $PATHпеременную. И поскольку любые программы, которые вы запускаете из приглашения bash, вызываются bash, новый путь действует для всего, что вы запускаете из приглашения bash.

Суть в том, что для добавления нового каталога к пути вы должны добавить или добавить каталог к ​​переменной среды $ PATH в сценарии, включенном в оболочку, и вы должны экспортировать $PATHпеременную среды.

Больше информации здесь

Стив Браун
источник
19

Уже некоторое время я держал со мной две функции pathaddи pathrmкоторые помогают в добавлении элементов в пути без необходимости беспокоиться о дупликации.

pathaddпринимает один аргумент пути и необязательный afterаргумент, который, если он указан, добавится к нему, в PATHпротивном случае он будет добавлен

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

pathadd() {
    newelement=${1%/}
    if [ -d "$1" ] && ! echo $PATH | grep -E -q "(^|:)$newelement($|:)" ; then
        if [ "$2" = "after" ] ; then
            PATH="$PATH:$newelement"
        else
            PATH="$newelement:$PATH"
        fi
    fi
}

pathrm() {
    PATH="$(echo $PATH | sed -e "s;\(^\|:\)${1%/}\(:\|\$\);\1\2;g" -e 's;^:\|:$;;g' -e 's;::;:;g')"
}

Поместите их в любой скрипт, который вы хотите изменить в среде PATH, и теперь вы можете это сделать.

pathadd "/foo/bar"
pathadd "/baz/bat" after
export PATH

Вы гарантированно не добавите к пути, если он уже есть. Если вы хотите, чтобы убедиться /baz/bat, в начале.

pathrm "/baz/bat"
pathadd "/baz/bat"
export PATH

Теперь любой путь может быть перемещен вперед, если он уже находится на пути без удвоения.

Бретт Райан
источник
Связанный и более чистый подход для проверки наличия каталога в вашем PATH: unix.stackexchange.com/a/32054/135943
Wildcard
9

Я не могу говорить о других дистрибутивах, но в Ubuntu есть файл / etc / environment, который является путем поиска по умолчанию для всех пользователей. Поскольку мой компьютер используется только мной, я помещаю туда любые каталоги, которые мне нужны, если только это не временное дополнение, которое я добавляю в скрипт.

Джим Брэдли
источник
6

В некоторых ситуациях его использование PATH=/a/b:$PATHможет считаться «неправильным» способом добавления пути к PATH:

  1. Добавление пути, который на самом деле не является каталогом.
  2. Добавление пути, который уже находится PATHв той же форме.
  3. Добавление относительного пути (поскольку фактический каталог будет изменяться при изменении текущего рабочего каталога).
  4. Добавление пути, который уже находится в PATHдругой форме (например, псевдоним из-за использования символических ссылок или ..).
  5. Если вы избегаете делать 4, не перемещайте путь вперед, PATHкогда он предназначен для переопределения других записей в PATH.

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

prepath() {
    local usage="\
Usage: prepath [-f] [-n] [-q] DIR
  -f Force dir to front of path even if already in path
  -n Nonexistent dirs do not return error status
  -q Quiet mode"

    local tofront=false errcode=1 qecho=echo
    while true; do case "$1" in
        -f)     tofront=true;       shift;;
        -n)     errcode=0;          shift;;
        -q)     qecho=':';          shift;;
        *)      break;;
    esac; done
    # Bad params always produce message and error code
    [[ -z $1 ]] && { echo 1>&2 "$usage"; return 1; }

    [[ -d $1 ]] || { $qecho 1>&2 "$1 is not a directory."; return $errcode; }
    dir="$(command cd "$1"; pwd -P)"
    if [[ :$PATH: =~ :$dir: ]]; then
        $tofront || { $qecho 1>&2 "$dir already in path."; return 0; }
        PATH="${PATH#$dir:}"        # remove if at start
        PATH="${PATH%:$dir}"        # remove if at end
        PATH="${PATH//:$dir:/:}"    # remove if in middle
    fi
    PATH="$dir:$PATH"
}

Исключением является то, что эта функция не канонизирует пути, добавленные с PATHпомощью других средств, поэтому, если неканонический псевдоним для пути включен PATH, это добавит дубликат. Попытка канонизировать уже существующие пути PATHявляется рискованным предложением, поскольку относительный путь имеет очевидное значение при передаче, prepathно когда он уже находится в пути, вы не знаете, каким был текущий рабочий каталог, когда он был добавлен.

Курт Дж. Сэмпсон
источник
Относительно относительных путей: как насчет наличия ключа -r, который бы добавил путь, не делая его первым абсолютным, и который также выглядел бы как абсолютный перед добавлением? Если бы это был сценарий, его можно было бы использовать в других оболочках. Есть ли какая-то польза от его использования в качестве функции? хороший код!
Hoijui
1
@hoijui Это должна быть функция, потому что она изменяет текущую среду. Если бы это был сценарий, он изменил бы среду подпроцесса, выполняющего сценарий, и при выходе из сценария вы бы получили то же, $PATHчто и раньше. Что касается -r, нет, я думаю, что относительные пути $PATHслишком ненадежны и странны (ваш путь меняется каждый раз, когда вы cd!), Чтобы хотеть поддерживать что-то подобное в общем инструменте.
Курт Дж. Сэмпсон
5

Для меня (в Mac OS X 10.9.5) добавление пути (например /mypathname) к файлу /etc/pathsработало очень хорошо.

Перед редактированием echo $PATHвозвращает:

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

После редактирования /etc/pathsи перезапуска оболочки к переменной $ PATH добавляется /pathname. Действительно, echo $PATHвозвращает:

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

То, что произошло, /mypathnameбыло добавлено к $PATHпеременной.

faelx
источник
3
Лучше добавить файл в каталог /etc/paths.d, чем редактировать сам файл / etc / paths.
rbrewer
4

Чтобы добавить новый путь к PATHпеременной среды:

export PATH=$PATH:/new-path/

Для этого изменения должны быть применены к любой оболочке вы открываете, добавьте его в файл , что оболочка источника , когда она вызывается. В разных оболочках это может быть:

  • Bash Shell: ~ / .bash_profile, ~ / .bashrc или профиль
  • Корн Шелл: ~ / .kshrc или .profile
  • Оболочка Z: ~ / .zshrc или .zprofile

например

# export PATH=$PATH:/root/learning/bin/
# source ~/.bashrc
# echo $PATH

Вы можете увидеть указанный путь в приведенном выше выводе.

Amit24x7
источник
4

Вот мое решение:

PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!x[$0]++' | sed "s/\(.*\).\{1\}/\1/")

Хороший легкий лайнер, который не оставляет след :

AJ.
источник
1
-bash: awk: Нет такого файла или каталога -bash: sed: Нет такого файла или каталога
davidcondrey
1
@davidcondrey - awk и sed - очень распространенные внешние команды. Этот ответ обеспечивает чистый способ достижения того же самого, поэтому он работает даже в тех случаях, когда awk и / или sed отсутствуют (или отсутствуют соответствующие каталоги!)
sancho.s