Дублирующие записи в $ PATH - проблема?

45

Я получаю bashrc от нескольких моих друзей. Таким образом, я получаю повторяющиеся записи в моей переменной $ PATH. Я не уверен, является ли это проблемой для команд, которые долго запускаются. Как внутренне работает $ PATH в bash? Имеет ли больше PATHS замедление моего запуска?

Балки
источник
Связанный: Добавить каталог в $ PATH, если его там еще нет (в Super User).
G-Man говорит «Восстановить Монику»

Ответы:

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
hwde
источник
1
Наиболее практичный (возможно, на высоком уровне) ответ.
Иосиф
3

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

Чтобы ответить на ваш вопрос: это не должно быть причиной медленного запуска.

Rajish
источник
1
Но это занимает больше времени, когда я набираю команду, которая не существует. Команда будет искать команду в одной и той же папке дважды.
Балки
@balki Вы имеете в виду выполнение команды с помощью TAB? В этом случае вы должны проверить, выглядит ли ваше полное определение complete -c which -a. Вы должны удалить -aпараметр. Вы можете проверить , что с помощью команды: complete | grep which.
Раджиш
Это все еще может быть проблемой, если он ищет тот же каталог, в котором его нет несколько раз, прежде чем найдет его.
Random832
-1

Чтобы предотвратить повторяющиеся записи в моем PATH, мне пришлось поместить в ОБА ~ ~. .Bash_profile и ~ / .bashrc следующее:

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

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

Джон Рейнольдс
источник
Порядок поиска PATH довольно важен.
Стивен Шоу