Contemplar! A função shell industrial de 12 linhas ... com capacidade industrial e zsh portátil que adora devotamente o seu script de inicialização ~/.bashrc
ou ~/.zshrc
de escolha:
# 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
}
Prepare-se para a glória instantânea. Então, ao invés de fazer isso e desejar o melhor:
export PATH=$PATH:~/opt/bin:~/the/black/goat/of/the/woods/with/a/thousand/young
Faça isso e tenha a garantia de obter o melhor, mesmo que você realmente queira ou não:
+path.append ~/opt/bin ~/the/black/goat/of/the/woods/with/a/thousand/young
Muito bem, defina "Melhor".
Anexar e anexar com segurança à corrente ${PATH}
não é o assunto trivial que costuma ser feito. Embora convenientes e aparentemente sensatos, as linhas de uma linha do formulário export PATH=$PATH:~/opt/bin
convidam complicações diabólicas com:
Nomes de diretório acidentalmente relativos (por exemplo, export PATH=$PATH:opt/bin
). Enquanto bash
e zsh
silenciosamente aceitar e principalmente ignorar dirnames relativas na maioria dos casos, dirnames relativos prefixado por qualquer h
ou t
(e possivelmente outros personagens nefastos) causa tanto para vergonhosamente se mutilam ala de Masaki Kobayashi seminal 1962 masterpiece Harakiri :
# 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.
Nomes de diretórios acidentalmente duplicados. Embora ${PATH}
nomes de diretórios duplicados sejam amplamente inócuos, eles também são indesejados, pesados, levemente ineficientes, impedem a depuração e promovem o desgaste da unidade - mais ou menos como esta resposta. Embora os SSDs do estilo NAND sejam (é claro ) imunes ao desgaste de leitura, os HDDs não são. O acesso desnecessário ao sistema de arquivos em cada comando tentado implica desgaste desnecessário da cabeça de leitura no mesmo ritmo. As duplicatas são particularmente untuosas ao invocar conchas aninhadas em subprocessos aninhados, nesse ponto aparentemente inofensivas como Não deixe isso acontecer com seus preciosos filhos. )export PATH=$PATH:~/wat
rapidamente explodem no Sétimo Círculo do ${PATH}
Inferno PATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat
. Somente o Beelzebubba pode ajudá-lo se você anexar nomes de diretório adicionais a ele. (
- Nomes de diretórios ausentes acidentalmente.Novamente, embora os
${PATH}
nomes de diretórios ausentes sejam amplamente inócuos, eles também são geralmente indesejados, pesados, levemente ineficientes, impedem a depuração e promovem o desgaste da unidade.
Ergo, automação amigável como a função shell definida acima. Nós devemos nos salvar de nós mesmos.
Mas ... Por que "+ path.append ()"? Por que não simplesmente append_path ()?
Por desambigüidade (por exemplo, com comandos externos nas ${PATH}
funções de shell atuais ou em todo o sistema definidas em outro lugar), as funções de shell definidas pelo usuário são idealmente prefixadas ou com sufixo com substrings exclusivos suportados por bash
e, de zsh
outra forma, proibidos para nomes de bases de comando padrão - como, por exemplo +
,.
Ei. Funciona. Não me julgue.
Mas ... Por que "+ path.append ()"? Por que não "+ path.prepend ()"?
Porque anexar à corrente ${PATH}
é mais seguro do que anexar à corrente ${PATH}
, todas as coisas sendo iguais, o que nunca são. A substituição de comandos em todo o sistema por comandos específicos do usuário pode ser insalubre na melhor das hipóteses e loucura na pior. No Linux, por exemplo, os aplicativos downstream normalmente esperam as variantes de comandos do GNU coreutils , em vez de derivadas ou alternativas não padronizadas personalizadas.
Dito isto, existem casos de uso válidos para isso. Definir a +path.prepend()
função equivalente é trivial. Sans prolix nebulosity, por sua sanidade compartilhada:
+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
}
Mas ... Por que não Gilles?
A resposta aceita de Gilles em outros lugares é impressionantemente ótima no caso geral como um "anexo idempotente independente de shell" . No caso comum de bash
e zsh
com não links simbólicos indesejáveis, no entanto, a pena de desempenho necessário para fazê-lo entristece o espremedor de Gentoo em mim. Mesmo na presença de links simbólicos indesejáveis, é discutível se bifurcar um subshell poradd_to_PATH()
argumento vale a inserção potencial de duplicatas simbólicos.
Para casos de uso rigorosos que exigem a eliminação de duplicatas de links simbólicos, essa zsh
variante específica faz isso por meio de componentes internos eficientes, em vez de garfos ineficientes:
+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
}
Observe o *":${dirname:A}:"*
invés *":${dirname}:"*
do original. :A
é um zsh
ismo maravilhoso tristemente ausente na maioria das outras conchas - inclusive bash
. Para citar man zshexpn
:
R : Transforme um nome de arquivo em um caminho absoluto, como o a
modificador, e passe o resultado pela realpath(3)
função de biblioteca para resolver os links simbólicos. Nota: em sistemas que não possuem uma realpath(3)
função de biblioteca, os links simbólicos não são resolvidos, portanto, nesses sistemas a
e A
são equivalentes.
Sem mais perguntas.
De nada. Desfrute de bombardeios seguros. Agora você merece.