Вот! Индустриальная мощная 12-строчная ... техническая bash- и zsh-переносимая функция оболочки, которая преданно любит ваш ~/.bashrc
или ~/.zshrc
запускаемый скрипт:
# void +path.append(str dirname, ...)
#
# Append each passed existing directory to the current user's ${PATH} in a
# safe manner silently ignoring:
#
# * Relative directories (i.e., *NOT* prefixed by the directory separator).
# * Duplicate directories (i.e., already listed in the current ${PATH}).
# * Nonextant directories.
+path.append() {
# For each passed dirname...
local dirname
for dirname; do
# Strip the trailing directory separator if any from this dirname,
# reducing this dirname to the canonical form expected by the
# test for uniqueness performed below.
dirname="${dirname%/}"
# If this dirname is either relative, duplicate, or nonextant, then
# silently ignore this dirname and continue to the next. Note that the
# extancy test is the least performant test and hence deferred.
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname}:"* &&
-d "${dirname}" ]] || continue
# Else, this is an existing absolute unique dirname. In this case,
# append this dirname to the current ${PATH}.
PATH="${PATH}:${dirname}"
done
# Strip an erroneously leading delimiter from the current ${PATH} if any,
# a common edge case when the initial ${PATH} is the empty string.
PATH="${PATH#:}"
# Export the current ${PATH} to subprocesses. Although system-wide scripts
# already export the ${PATH} by default on most systems, "Bother free is
# the way to be."
export PATH
}
Приготовься к мгновенной славе. Тогда, вместо того чтобы делать это и желать надежды на лучшее:
export PATH=$PATH:~/opt/bin:~/the/black/goat/of/the/woods/with/a/thousand/young
Сделайте это вместо этого и будьте уверены, что получите лучшее, действительно ли вы этого хотели или нет:
+path.append ~/opt/bin ~/the/black/goat/of/the/woods/with/a/thousand/young
Отлично, определите «лучший».
Безопасное добавление и добавление к току ${PATH}
не является обычным делом. В то время как удобные и кажущиеся разумными, однострочники формы export PATH=$PATH:~/opt/bin
вызывают дьявольские осложнения с:
Случайно относительные dirnames (например, export PATH=$PATH:opt/bin
). Хотя в большинстве случаев bash
и zsh
безмолвно принимают и в основном игнорируют относительные имена dirname , относительные имена dirnames с префиксом либо или (и, возможно, других гнусных персонажей) заставляют обоих позорно изуродовать себя оригинальным шедевром аля Масаки Кобаяши 1962 года Харакири :h
t
# Don't try this at home. You will feel great pain.
$ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:harakiri && echo $PATH
/usr/local/bin:/usr/bin:arakiri
$ PATH='/usr/local/bin:/usr/bin:/bin' && export PATH=$PATH:tanuki/yokai && echo $PATH
binanuki/yokai # Congratulations. Your system is now face-up in the gutter.
Случайно дублируйте имена. Хотя дубликаты ${PATH}
каталогов в основном безвредны, они также нежелательны, громоздки, слегка неэффективны, затрудняют отладку и способствуют износу дисков - как этот ответ. Хотя твердотельные накопители в стиле NAND ( конечно ) не подвержены износу при чтении, жесткие диски - нет. Ненужный доступ к файловой системе при каждой попытке команды подразумевает ненужный износ считывающей головки в одном и том же темпе. Дубликаты особенно неуместны, когда вызывают вложенные оболочки в вложенных подпроцессах, и в этот момент кажущиеся безобидными однострочники export PATH=$PATH:~/wat
быстро взрываются, как Седьмой круг ${PATH}
ада PATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat
. Только Вельзевул может помочь вам, если вы добавите к этому дополнительные имена. (Не позволяй этому случиться с твоими драгоценными детьми. )
- Случайно пропущенные имена. Опять же, несмотря на то, что пропущенные
${PATH}
имена каталогов в основном безвредны, они также обычно нежелательны, громоздки, слегка неэффективны, препятствуют отладке и способствуют износу дисков.
Ergo, дружественная автоматизация, подобная функции оболочки, определенной выше. Мы должны спасти себя от самих себя.
Но ... Почему "+ path.append ()"? Почему не просто append_path ()?
Для disambiguity (например, с внешними командами в текущей ${PATH}
или всей системе функций оболочки , определенных в другом месте), определяемого пользователь функция оболочки идеально приставка или суффикс с уникальными подстроками , поддерживаемых bash
и , zsh
но иным образом запрещена для стандартных команд basenames - как, скажем, +
.
Привет. Оно работает. Не суди меня.
Но ... Почему "+ path.append ()"? Почему бы не "+ path.prepend ()"?
Поскольку присоединение к току ${PATH}
безопаснее, чем присоединение к току ${PATH}
, все вещи равны, а они никогда не равны. Переопределение общесистемных команд пользовательскими командами в лучшем случае может быть антисанитарным, а в худшем - безумным. Например, в Linux нижестоящие приложения обычно ожидают варианты команд GNU coreutils, а не нестандартные нестандартные производные или альтернативы.
Тем не менее, есть абсолютно допустимые варианты использования для этого. Определение эквивалентной +path.prepend()
функции тривиально. Sans prolix nebulosity, для его и ее общего здравомыслия:
+path.prepend() {
local dirname
for dirname in "${@}"; do
dirname="${dirname%/}"
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname}:"* &&
-d "${dirname}" ]] || continue
PATH="${dirname}:${PATH}"
done
PATH="${PATH%:}"
export PATH
}
Но ... Почему не Жиль?
Жиля ' приемлемого ответа в другом месте выразительно оптимальный в общем случае в виде „оболочка агностического идемпотентного Append“ . Однако в обычном случае bash
и zsh
при отсутствии нежелательных символических ссылок потеря производительности, требуемая для этого, огорчает меня в Gentoo . Даже при наличии нежелательных симлинок, это спорно ли разветвление один подоболочки в add_to_PATH()
аргумент стоит потенциала вставки символических ссылок дублей.
Для строгих случаев использования, требующих устранения даже дубликатов символических ссылок, этот zsh
-специфичный вариант делает это с помощью эффективных встроенных функций, а не неэффективных вилок:
+path.append() {
local dirname
for dirname in "${@}"; do
dirname="${dirname%/}"
[[ "${dirname:0:1}" == '/' &&
":${PATH}:" != *":${dirname:A}:"* &&
-d "${dirname}" ]] || continue
PATH="${PATH}:${dirname}"
done
PATH="${PATH#:}"
export PATH
}
Обратите внимание, *":${dirname:A}:"*
а не *":${dirname}:"*
оригинал. :A
Удивительный zsh
-изм, к сожалению, отсутствует в большинстве других оболочек - в том числе bash
. Цитировать man zshexpn
:
A : Превратите имя файла в абсолютный путь, как это a
делает модификатор, а затем передайте результат через realpath(3)
библиотечную функцию для разрешения символических ссылок. Примечание: на системах , которые не имеют realpath(3)
функции библиотеки, символические ссылки не будут решены, так что в этих системах a
и A
эквивалентны.
Больше нет вопросов.
Пожалуйста. Наслаждайтесь безопасным обстрелом. Теперь вы это заслужили.