Duplicar entradas em $ PATH é um problema?


45

Eu fonte de bashrc de alguns dos meus amigos. Então, acabo tendo entradas duplicadas na minha variável $ PATH. Não tenho certeza se esse é o problema dos comandos que demoram para iniciar. Como o $ PATH trabalha internamente no bash? Ter mais CAMINHOS diminui o tempo de inicialização?




Respostas:


42

Ter mais entradas $PATHnão diminui a velocidade da inicialização diretamente, mas diminui a cada vez que você executa um comando específico em uma sessão de shell (nem sempre que o comando é executado, porque o bash mantém um cache). A desaceleração raramente é perceptível, a menos que você tenha um sistema de arquivos particularmente lento (por exemplo, NFS, Samba ou outro sistema de arquivos de rede ou no Cygwin).

Entradas duplicadas também são um pouco irritantes quando você revisa $PATHvisualmente, você precisa percorrer mais coisas.

É fácil o suficiente para evitar adicionar entradas duplicadas.

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

Nota lateral: obter o script shell de outra pessoa significa executar o código que ele escreveu. Em outras palavras, você está dando a seus amigos acesso à sua conta sempre que eles quiserem.

Nota lateral: .bashrcnão é o local certo para configurar $PATHou qualquer outra variável de ambiente. As variáveis ​​de ambiente devem ser definidas ~/.profile. Consulte Quais arquivos de instalação devem ser usados ​​para configurar variáveis ​​de ambiente com o bash? , Diferença entre .bashrc e .bash_profile .


8
+1: não é possível enfatizar que "dando acesso a sua conta a seus amigos" é suficiente. Mesmo que não haja nenhuma tentativa de prejudicá-lo, o script deles pode ser exatamente o que eles precisam e ainda assim almoçar quando você o buscar.
msw

Um possível problema com esta solução é se $ new_entry já for a primeira entrada no PATH, o ": $ new_entry:" não corresponderá. Corrigi isso no meu perfil excluindo os dois pontos iniciais ':'.
Jeff Bauer

@JeffBauer Não vejo o problema. Eu uso case :$PATH:e não case $PATHpara que corresponda, mesmo que a entrada seja a primeira ou a última.
Gilles 'SO- stop be evil'

31

Eu já vi pessoas limparem duplicatas de suas variáveis ​​PATH usando awkalgo assim:

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

Você pode tentar adicionar isso ao seu próprio bashrc e garantir a fonte dos outros arquivos em algum lugar antes de executá-lo.

Uma alternativa seria usar opathmerge utilitário.

Quanto ao seu problema de velocidade, isso não afetará o tempo de inicialização do shell de maneira significativa, mas poderá poupar algum tempo na conclusão da guia de comandos, especialmente quando o comando não for encontrado no caminho e ele realizar buscas repetidas no mesmo pastas procurando por ele.

Uma observação sobre segurança: você deve realmente prestar atenção às advertências de Gilles sobre segurança aqui. Ao adquirir um arquivo de propriedade de outro usuário, você está dando um passe livre para que esses usuários executem seu próprio código como seu usuário toda vez que iniciar um shell. Se você não confia na senha desses usuários, não deve fornecer os arquivos de shell deles.


6
Eu gosto do one-liner awk, mas ele imprime um ORS ':' à direita. Então eu modifiquei-o para lerPATH=$(echo "$PATH" | awk -v RS=':' -v ORS=":" '!a[$1]++{if (NR > 1) printf ORS; printf $a[$1]}')
gkb0986

A fuga :não é apenas uma questão cosmética. É o mesmo que adicionar .ao seu caminho, o que é potencialmente perigoso.
wisbucky

Editei a resposta para incluir a correção de gkb0986.
precisa saber é o seguinte

@ TimLesher A razão pela qual eu nunca editei a resposta foi que não funciona para mim .... e o original sem ele funciona (inclusive não deixando um separador à direita. Não sei qual é a diferença .
Caleb

1
@ gkb0986 Esta solução ainda falha se o caminho contiver um espaço de escape, como PATH = / bin: / foo \ bar: / usr / bin. Eu encontrei uma variante que evita isso em unix.stackexchange.com/a/124517/106102
maharvey67

13

Com base na resposta do @Gilles, você pode agrupá-la em uma função para minimizar a digitação:

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
Resposta mais praticamente utilizável (de alto nível, talvez).
ijoseph

3

Somente a primeira correspondência $PATHé executada, portanto, as entradas subsequentes não são processadas depois disso. É por isso que às vezes você deve revisar a ordem das entradas no seu $PATHpara fazer com que seu ambiente se comporte conforme o esperado.

Para responder à sua pergunta: isso não deve ser a causa da inicialização lenta.


1
Mas leva mais tempo quando digito um comando que não existe. Ele procurará a mesma pasta duas vezes pelo comando.
balki

@balki Você quer dizer completar um comando TAB? Nesse caso, você deve verificar se a definição completa não se parece complete -c which -a. Você deve excluir o -aparâmetro Você pode verificar que, ao emitir o comando: complete | grep which.
Rajish

Ainda pode ser um problema se ele pesquisar o mesmo diretório em que ele não está várias vezes antes de encontrá-lo.
Random832

-1

Para evitar entradas duplicadas no meu PATH, tive que colocar o seguinte em AMBOS ~ / .bash_profile e ~ / .bashrc:

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

A principal desvantagem é que ele classifica as entradas PATH, mas acho que posso conviver com isso.


A ordem da busca PATH é bastante importante.
Steven Shaw
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.