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?

balki
fonte

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 .

Gilles 'SO- parar de ser mau'
fonte
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.

Caleb
fonte
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
hwde
fonte
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.

Rajish
fonte
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.

John Reynolds
fonte
A ordem da busca PATH é bastante importante.
Steven Shaw