Las entradas duplicadas en $ PATH son un problema?

45

Obtengo bashrc de algunos de mis amigos. Así que termino teniendo entradas duplicadas en mi variable $ PATH. No estoy seguro de si ese es el problema para los comandos que tardan mucho en iniciarse. ¿Cómo funciona $ PATH internamente en bash? ¿Tener más CAMINOS ralentiza mi tiempo de inicio?

balki
fuente

Respuestas:

42

Tener más entradas $PATHno ralentiza directamente su inicio, pero se ralentiza cada vez que ejecuta un comando en particular en una sesión de shell (no cada vez que ejecuta el comando, porque bash mantiene un caché). La ralentización rara vez es perceptible a menos que tenga un sistema de archivos particularmente lento (por ejemplo, NFS, Samba u otro sistema de archivos de red, o en Cygwin).

Las entradas duplicadas también son un poco molestas cuando $PATHrevisas tu visualmente, tienes que atravesar más cruft.

Es bastante fácil evitar agregar entradas duplicadas.

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

Nota al margen: obtener el script de shell de otra persona significa ejecutar el código que ha escrito. En otras palabras, le está dando a sus amigos acceso a su cuenta cuando lo deseen.

Nota al margen: .bashrcno es el lugar correcto para establecer $PATHni ninguna otra variable de entorno. Las variables de entorno deben establecerse ~/.profile. Consulte ¿Qué archivos de configuración deben usarse para configurar variables de entorno con bash? , Diferencia entre .bashrc y .bash_profile .

Gilles 'SO- deja de ser malvado'
fuente
8
+1: no puedo enfatizar que "darle a tus amigos acceso a tu cuenta" suficiente énfasis. Incluso si no hay ningún intento de hacerte daño, su guión podría ser justo lo que necesitan y aún así comer tu almuerzo cuando lo obtengas.
msw
Un posible problema con esta solución es que si $ new_entry ya es la primera entrada en PATH, ": $ new_entry:" no coincidirá. Lo arreglé en mi perfil al excluir los dos puntos ':' iniciales.
Jeff Bauer
@JeffBauer No veo el problema. Yo uso case :$PATH:y no case $PATHpara que coincida incluso si la entrada es la primera o la última.
Gilles 'SO- deja de ser malvado'
31

He visto a personas limpiar duplicados de su variable PATH usando awky algo como esto:

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

Puede intentar agregar eso a su propio bashrc y asegurarse de obtener los otros archivos en algún lugar antes de ejecutarlo.

Una alternativa sería usar lapathmerge utilidad.

En cuanto a su problema de velocidad, esto no afectará el tiempo de inicio del shell de manera significativa, pero puede ahorrar algo de tiempo al completar la pestaña para los comandos, especialmente cuando el comando no se encuentra en la ruta y realiza búsquedas repetidas a través del mismo carpetas buscándolo.

Una nota sobre seguridad: realmente deberías prestar atención a las advertencias de Gilles sobre seguridad aquí. Al obtener un archivo propiedad de otro usuario, le está dando un pase gratuito a esos usuarios para que ejecuten su propio código como usuario cada vez que inicie un shell. Si no confías en esos usuarios con tu contraseña, no deberías buscar sus archivos shell.

Caleb
fuente
66
Me gusta el awk one-liner, pero imprime un ORS final ':'. Así que lo modifiqué para leerPATH=$(echo "$PATH" | awk -v RS=':' -v ORS=":" '!a[$1]++{if (NR > 1) printf ORS; printf $a[$1]}')
gkb0986 el
El seguimiento :no es solo un problema cosmético. Es lo mismo que agregar .a su camino, que es potencialmente peligroso.
wisbucky
He editado la respuesta para incluir la solución de gkb0986.
Tim Lesher
@TimLesher La razón por la que nunca había editado más que por respuesta es que no funciona para mí ... y el original sin él funciona (incluyendo no dejar un separador final. No sé cuál es la diferencia .
Caleb
1
@ gkb0986 Esta solución aún falla si la ruta contiene un espacio escapado, como PATH = / bin: / foo \ bar: / usr / bin. Encontré una variante que evita esto en unix.stackexchange.com/a/124517/106102
maharvey67
13

Según la respuesta de @Gilles, puede envolverlo en una función para minimizar la escritura:

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
fuente
1
La respuesta más práctica (de alto nivel, tal vez).
ijoseph
3

Solo $PATHse ejecuta la primera coincidencia , por lo que las entradas posteriores no se procesan después de eso. Es por eso que a veces debe revisar el orden de las entradas en su $PATHpara que su entorno se comporte como se espera.

Para responder a su pregunta: esta no debería ser la causa del inicio lento.

Rajish
fuente
1
Pero lleva más tiempo cuando escribo un comando que no existe. Buscará la misma carpeta dos veces para el comando.
balki
@balki ¿Te refieres a completar un comando con TAB? En ese caso, debe verificar si no completa la definición complete -c which -a. Deberías eliminar el -aparámetro. Se puede comprobar que al emitir el comando: complete | grep which.
Rajish
Todavía podría ser un problema si busca el mismo directorio en el que no está varias veces antes de encontrarlo.
Random832
-1

Para evitar entradas duplicadas en mi RUTA, tuve que poner lo siguiente en AMBOS ~ / .bash_profile y ~ / .bashrc:

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

El principal inconveniente es que clasifica las entradas de RUTA, pero creo que puedo vivir con eso.

John Reynolds
fuente
El orden de la ruta de búsqueda es bastante importante.
Steven Shaw