Дублювання записів у $ PATH проблема?


45

Я джерело bashrc небагатьох моїх друзів. Отже, у мене є дублікати записів у моїй змінній $ PATH. Я не впевнений, чи це проблема для команд, які потребують довгого запуску. Як внутрішньо працює $ PATH в bash? Чи більша кількість ПАТХ уповільнює час мого запуску?




Відповіді:


42

Наявність більшої кількості записів $PATHбезпосередньо не уповільнює ваш запуск, але це повільно, коли ви вперше запускаєте певну команду під час сеансу оболонки (не кожен раз, коли ви запускаєте команду, оскільки bash підтримує кеш). Уповільнення рідко відчутно, якщо у вас немає особливо повільної файлової системи (наприклад, NFS, Samba або іншої мережевої файлової системи або на Cygwin).

Дублікати записів також трохи дратують, коли ви переглядаєте $PATHвізуально, вам доведеться пройти більше чіткості.

Досить просто уникати додавання дублікатів.

case ":$PATH:" in
  *":$new_entry:"*) :;; # already there
  *) PATH="$new_entry:$PATH";; # or PATH="$PATH:$new_entry"
esac

Побічна примітка: пошук чужого скрипта оболонки означає виконання коду, який він написав. Іншими словами, ви надаєте друзям доступ до свого облікового запису, коли вони захочуть.

Бічна примітка: .bashrcце не правильне місце для встановлення $PATHчи будь-якої іншої змінної середовища. Змінні середовища повинні бути встановлені ~/.profile. Див. Які файли налаштування слід використовувати для налаштування змінних оточуючих середовищ за допомогою bash? , Різниця між .bashrc та .bash_profile .


8
+1: не можу підкреслити, що "надання друзям доступу до вашого облікового запису" достатньо уваги. Навіть якщо немає спроби зробити вам шкоду, їх сценарій може бути саме тим, що їм потрібно, і все-таки з'їсти ваш обід, коли ви його отримаєте.
msw

Одне з можливих проблем із цим рішенням - якщо $ new_entry вже є першим записом у PATH, ": $ new_entry:" не збігатиметься. Я виправив це у своєму профілі, виключивши початкову двокрапку ':'.
Джефф Бауер

@JeffBauer Я не бачу проблеми. Я використовую case :$PATH:і не case $PATHтак, щоб він відповідав, навіть якщо запис є першим чи останнім.
Жиль "ТАК - перестань бути злим"

31

Я бачив, як люди чистять дублікати зі своєї змінної PATH, використовуючи awkщось подібне:

PATH=$(printf "%s" "$PATH" | awk -v RS=':' '!a[$1]++ { if (NR > 1) printf RS; printf $1 }')

Ви можете спробувати додати це до власного bashrc та переконайтесь, що ви інші джерела десь запустили, перш ніж це запустити.

Альтернативи можна було б використовувати наpathmerge корисність.

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

Примітка про безпеку: Ви дійсно повинні прислухатися до попереджень Гілла щодо безпеки тут. Створюючи файл, що належить іншому користувачеві, ви отримуєте безкоштовний пропуск для тих користувачів, щоб виконувати власний код як ваш користувач щоразу, коли ви запускаєте оболонку. Якщо ви не довіряєте цим користувачам свій пароль, вам не слід шукати файли оболонки.


6
Мені подобається одношаровий awk, але він друкує кінцевий ORS ':'. Тому я змінив його на читанняPATH=$(echo "$PATH" | awk -v RS=':' -v ORS=":" '!a[$1]++{if (NR > 1) printf ORS; printf $a[$1]}')
gkb0986

Послідовність :- це не лише косметичне питання. Це те саме, що додавати .до вашого шляху, який є потенційно небезпечним.
wisbucky

Я відредагував відповідь, щоб включити виправлення з gkb0986.
Тім Лешер

@TimLesher Причина, яку я ніколи не редагував, ніж у відповідь, полягає в тому, що вона не працює для мене .... і оригінал без цього не працює (в тому числі не залишаючи зворотного роздільника. Я не знаю, в чому різниця .
Калеб

1
@ gkb0986 Це рішення все ж не вдається, якщо шлях містить пробіл, такий як PATH = / bin: / foo \ bar: / usr / bin. Я знайшов варіант, який уникає цього, на unix.stackexchange.com/a/124517/106102
maharvey67

13

На підставі відповіді @Gilles ви можете перетворити його на функцію, щоб мінімізувати введення тексту:

function addToPATH {
  case ":$PATH:" in
    *":$1:"*) :;; # already there
    *) PATH="$1:$PATH";; # or PATH="$PATH:$1"
  esac
}

addToPATH /Applications/AIRSDK_Compiler/bin
addToPATH ~/.local/lib/npm/bin

1
Найбільш практична відповідь (високий рівень, можливо,) відповідь.
ійосеф

3

Виконується лише перший збіг у $PATH, тому всі наступні записи після цього не обробляються. Ось чому вам іноді слід переглянути порядок записів у $PATHвашому середовищі, щоб ваше середовище поводилось так, як очікувалося.

Щоб відповісти на ваше запитання: це не повинно бути причиною повільного запуску.


1
Але це займе більше часу, коли я набираю команду, яка не існує. Він буде шукати одну і ту ж папку двічі для команди.
балки

@balki Ви маєте на увазі виконання команди TAB? У такому випадку слід перевірити, чи не виглядає ваше повне визначення complete -c which -a. Ви повинні видалити -aпараметр. Ви можете перевірити , що з допомогою команди: complete | grep which.
Раджиш

Це все ще може бути проблемою, якщо він шукатиме той самий каталог, який він не є декілька разів, перш ніж його знайти.
Випадково832

-1

Для запобігання повторюваних записів у моєму PATH мені довелося вказати наступне у BOTH ~ / .bash_profile та ~ / .bashrc:

PATH=$(echo $(sed 's/:/\n/g' <<< $PATH | sort | uniq) | sed -e 's/\s/':'/g')

Основним недоліком є ​​те, що він сортує записи PATH, але я думаю, що я можу з цим жити.


Порядок пошуку PATH є досить важливим.
Стівен Шоу
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.