Як правильно додати шлях до PATH?


921

Мені цікаво, де до PATHзмінної середовища потрібно додати новий шлях . Я знаю, що це можна досягти шляхом редагування .bashrc(наприклад), але незрозуміло, як це зробити.

Сюди:

export PATH=~/opt/bin:$PATH

чи це?

export PATH=$PATH:~/opt/bin

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

Відповіді:


1033

Прості речі

PATH=$PATH:~/opt/bin

або

PATH=~/opt/bin:$PATH

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

Ви можете одночасно додати кілька записів. PATH=$PATH:~/opt/bin:~/opt/node/binабо варіації замовлення працюють просто чудово. Не ставте exportна початку рядка, оскільки це має додаткові ускладнення (див. Нижче "Примітки до снарядів, окрім удару").

Якщо ваші PATHпобудовані багатьма різними компонентами, у вас можуть з’явитися повторювані записи. Див. Як додати шлях до домашнього каталогу для виявлення Unix, яка команда? та видаліть повторювані записи $ PATH командою awk, щоб уникнути додавання дублікатів або видалення їх.

Деякі дистрибутиви ~/bin, до речі, автоматично поміщаються у ваш PATH, якщо він існує.

Куди його поставити

Помістіть лінію , щоб змінити PATHв ~/.profile, або , ~/.bash_profileякщо це те, що у вас є.

Зауважте, що ~/.bash_rcне читається жодною програмою і ~/.bashrcє файлом конфігурації інтерактивних екземплярів bash. Не слід визначати змінні середовища у ~/.bashrc. Правильне місце для визначення змінних оточуючих середовищ, таких як PATHє ~/.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, таких як тире (який є /bin/shу багатьох системах), exportаналізується як звичайна команда, що передбачає дві відмінності:

Отже, в оболонках, як тире, 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і не зробила розширення tilde).

¹ Це не було правдою для снарядів Борна (як у власне оболонці Борна, а не сучасних снарядів у стилі POSIX), але ви навряд чи зустрінетесь із такими старими снарядами в наші дні.


Досі не в змозі зрозуміти ускладнення з експортом. ви можете, будь ласка, спростити його?
priojeet priyom

@priojeetpriyom Просте пояснення: вам не потрібно export.
Жиль

Дякую за цю відповідь, ідеально докладно. Ви кажете " Не слід визначати змінні середовища в ~ / .bashrc ", але, на жаль, 100% програм, встановлених у моїй системі, які змінюють шлях (FZF та Rust's Cargo), змінюють шлях у .bashrc. Я припускаю, що FZF написаний також на Rust, він слідує шаблону Іржі.
icc97

83

Так чи інакше працює, але вони не роблять те ж саме: елементи PATHперевіряються зліва направо. У вашому першому прикладі виконувані файли у файлі ~/opt/binматимуть перевагу над встановленими, наприклад, у /usr/bin, у яких може бути або не бути тим, що ви хочете.

Зокрема, з точки зору безпеки, небезпечно додавати шляхи на фронт, оскільки якщо хтось може отримати доступ до запису до вас ~/opt/bin, він може поставити, наприклад, інший lsтам, який ви, ймовірно, замість цього використаєте з того /bin/lsне помічаючи. Тепер уявіть те саме для sshвашого веб-переглядача чи вибору ... (Те ж саме потроху стосується введення. У ваш шлях.)


6
Але якщо ви хочете мати свою власну, підганяну версію ls, вам потрібно покласти її в каталог до цього /bin.
Бармар

16
або псевдонім ls = myls
waltinator

36

Мене бентежить питання 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нуль або не встановлено, нічого не замінюється, інакше розширення wordзамінено.

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

Примітка . Це для баш.


* 1 Я щойно виявив, що такі сценарії, як devtoolset-6/enableнасправді, використовують це,

$ cat /opt/rh/devtoolset-6/enable
# General environment variables
export PATH=/opt/rh/devtoolset-6/root/usr/bin${PATH:+:${PATH}}
...

24

Linux визначає виконуваний шлях пошуку за допомогою $PATHзмінної середовища. Щоб додати каталог / дані / скрипти до початку $PATHзмінної середовища, використовуйте наступне:

PATH=/data/myscripts:$PATH

Щоб додати цей каталог до кінця шляху, використовуйте таку команду:

PATH=$PATH:/data/myscripts

Але попереднього недостатньо, оскільки коли ви встановлюєте змінну середовища всередині сценарію, ця зміна є ефективною лише в сценарії. Навколо цього обмеження існують лише два способи:

  • Якщо в рамках сценарію, ви експортуєте змінну середовища, це ефективно в будь-яких програмах, викликаних сценарієм. Зауважте, що це не ефективно в програмі, яка викликала сценарій.
  • Якщо програма, яка викликає скрипт, робить це шляхом включення замість виклику, будь-які зміни середовища в сценарії є ефективними в рамках програми виклику. Таке включення може бути виконано за допомогою команди dot або вихідної команди.

Приклади:

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

Включення в основному включає в себе "викликаний" скрипт в "дзвінкий" сценарій. Це як #include в C. Отже, це ефективно всередині "дзвінка" сценарію або програми. Але, звичайно, це не ефективно в будь-яких програмах або скриптах, викликаних програмою, що викликає. Щоб зробити його ефективним у всьому ланцюзі викликів, ви повинні дотримуватися налаштування змінної оточення за допомогою команди експорту.

Наприклад, програма bash shell містить вміст файлу .bash_profile шляхом включення. Помістіть у .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змінної.


3
Краще додати файл у каталог /etc/paths.d, ніж редагувати сам файл / etc / paths.
rbrewer

4

Щоб додати новий шлях до PATHзмінної середовища:

export PATH=$PATH:/new-path/

Для цього зміни повинні бути застосовані до будь-якої оболонці ви відкриваєте, додайте його в файл , що оболонка джерела , коли вона викликається. У різних оболонках це може бути:

  • Bash Shell: ~ / .bash_profile, ~ / .bashrc або профіль
  • Korn Shell: ~ / .kshrc або .profile
  • Z Shell: ~ / .zshrc або .zprofile

напр

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

Ви можете побачити наданий шлях у наведеному вище висновку.


4

Ось моє рішення:

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

Приємний простий вкладиш, який не залишає сліду :


1
-bash: awk: Немає такого файлу чи каталогу -bash: sed: Немає такого файлу чи каталогу
davidcondrey

1
@davidcondrey - awk і sed - дуже поширені зовнішні команди. Ця відповідь забезпечує чисто-баш-спосіб досягнення того ж, тому він працює навіть у випадках, коли awk та / або sed немає (або їхні каталоги не в дорозі!)
sancho.s
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.