Pode entradas duplicadas de la variable PATH

9

Modifico mi .bashrc con frecuencia y luego lo obtengo. Sin embargo, cuando tengo cosas como export PATH="~/bin:~/perl5/bin:$PATH"en mi archivo, la PATHvariable de entorno crece cada vez que obtengo el archivo.

Por ejemplo, la primera vez que se obtiene .bashrc, la PATHvariable consiste en ~/bin:~/perl5/bin:/usr/bin:/bin.

La segunda vez que consiste ~/bin:~/perl5/bin:~/bin:~/perl5/bin:/usr/bin:/bin.

La tercera vez que consiste ~/bin:~/perl5/bin:~/bin:~/perl5/bin:~/bin:~/perl5/bin:/usr/bin:/bin.

¿Hay una manera simple de hacer que solo agregue algo que no esté ya en la RUTA?

Christopher Bottoms
fuente

Respuestas:

12

Utilice la función pathmunge () disponible en la mayoría de las distribuciones /etc/profile:

pathmunge () {
if ! echo $PATH | /bin/egrep -q "(^|:)$1($|:)" ; then
   if [ "$2" = "after" ] ; then
      PATH=$PATH:$1
   else
      PATH=$1:$PATH
   fi
fi
}

editar : para los zshusuarios, typeset -U <variable_name>deduplicará las entradas de ruta.

Sam Halicke
fuente
¡Gracias! No está en /etc/profileDebian Lenny, así que lo incluyo en mi .bashrc.
Christopher Bottoms
Uso: pathmunge /some/pathse colocará /some/pathal principio de $PATHy pathmunge /some/path afterse colocará /some/pathal final de$PATH
Christopher Bottoms
Forma más limpia de hacer la comprobación para ver si existe el directorio Hew en la ruta actual, en las modernas conchas de bash: if ! [[ $PATH =~ (^|:)$1($|:) ]] ; then.
Christopher Cashell
Yo no usaría esto. Si mi versión ingenua decía PATH = / foo: $ PATH eso significa que quiero que / foo gane. pathmunge /foo beforeno logra eso. Una mejor manera sería agregar / foo al principio y luego eliminar los duplicados después.
Don Hatch
3

Estaba teniendo este problema, así que usé una combinación de técnicas enumeradas en la pregunta de StackOverflow . Lo siguiente es lo que solía deducir la variable PATH real que ya se había establecido, ya que no quería modificar el script base.

    tmppath=(${PATH// /@})
    array=(${tmppath//:/ })
    for i in "${array[@]//@/ }"
    do
        if ! [[ $PATH_NEW =~ "$i" ]]; then
            PATH_NEW="${PATH_NEW}$i:";
        fi
    done;
    PATH="${PATH_NEW%:}"
    export PATH
    unset PATH_NEW

Siempre podría optimizar esto un poco más, pero tenía un código adicional en mi original para mostrar lo que estaba sucediendo para asegurarme de que estaba configurando correctamente las variables. La otra cosa a tener en cuenta es que realizo lo siguiente

  1. reemplazar cualquier caracter de ESPACIO con un caracter @
  2. dividir la matriz
  3. recorrer el conjunto
  4. reemplace cualquier @ caracteres en la cadena de elementos con un espacio

Esto es para garantizar que pueda manejar directorios con espacios en (¡los directorios de inicio de Samba con nombres de usuario de Active Directory pueden tener espacios!)

netniV
fuente
ADVERTENCIA: ¡Esta implementación tiene un error importante! ¡se eliminará /binsi hay otras entradas como /usr/binporque la expresión regular coincide aunque las dos entradas no sean iguales!
Sukima
Aquí hay una implementación alternativa que corrige ese error: github.com/sukima/dotfiles/blob/…
Sukima
1

Establece tu camino explícitamente.

Cakemox
fuente
Gracias. Intenté configurar la ruta explícitamente, pero tengo un archivo .bashrc que uso en múltiples entornos, por lo que el valor predeterminado exacto PATHno siempre es el mismo.
Christopher Bottoms
1

Solo una cadena:

for i in $(echo $PATH|tr ":" "\n"|sort|uniq);do PATH_NEW="${PATH_NEW}$i:";done;PATH="${PATH_NEW%:}"
bindbn
fuente
Gracias. Una de las dificultades que esto me causaría es que reordena alfabéticamente (o ASCIIbeticamente) el contenido de $PATH. Me gusta poner directorios específicos al principio de $PATH(like /home/username) para que mis copias personales de ejecutables se ejecuten en lugar de los valores predeterminados incorporados.
Christopher Bottoms
1

Se me ocurren dos formas diferentes de resolver esto. El primero, es iniciar su .bashrc con una línea que establezca explícitamente su RUTA base, de esa manera cada vez que la obtiene, se restablece a la base antes de agregar directorios adicionales.

Por ejemplo, agregue:

# Reset the PATH to prevent duplication and to make sure that we include
# everything we want.
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Alternativamente, puede verificar un elemento antes de agregarlo a la ruta. Para hacer eso, usarías algo como:

if ! [[ $PATH =~ '~/perl5/bin' ]]
then
    PATH="~/perl5/bin:$PATH"
fi

Sin embargo, este último tiende a ser un poco repetitivo si agrega muchas entradas, por lo que tiendo a seguir con el primero. Si desea usar esto y planea agregar muchas entradas, sería aconsejable escribir una función bash para manejarlo.

Nota: La segunda opción solo puede funcionar como está escrita en las versiones modernas de bash. El soporte de expresiones regulares no es una característica de Bourne Shell (/ bin / sh) y puede no existir en otros shells. Además, el uso de comillas puede no ser necesario o incluso puede causar problemas en algunas versiones más recientes de bash.

Christopher Cashell
fuente
Gracias. Intenté configurar la ruta explícitamente, pero tengo un archivo .bashrc que uso en múltiples entornos, por lo que el valor predeterminado exacto PATHno siempre es el mismo.
Christopher Bottoms
Todavía puede manejar eso al verificar el script para ver cuál es su nombre de host local y luego configurar su ruta absoluta de manera adecuada para ese servidor.
Christopher Cashell
Solo un error tipográfico: el! falta en el if. Además, es sorprendentemente (para mí) fácil convertir esto en una función que recorre los argumentos separados por espacios, por lo que puede decir: add_to_PATH ~/perl5/bin ~/.bin unix.stackexchange.com/a/4973/28760 (supongo que la casedeclaración utilizada allí es más portátil , pero tu ifes más claro para mí). ¡EDITE una extraña coincidencia de que esa pregunta también agregue perl5!
13ren
@ 13ren: Gracias por la nota. También me di cuenta de que usaba comillas simples en la línea de conjunto PATH, en lugar de comillas dobles como debería haber hecho. Como está escrito, habría reemplazado su ruta existente con el nombre de la variable. ¡Uy! Aparentemente fue una mala entrada para los errores tipográficos; ambos están arreglados ahora.
Christopher Cashell
0

Aquí está mi solución: PATH=$(echo -n $PATH | awk -v RS=: -v ORS=: '!x[$0]++' | sed "s/\(.*\).\{1\}/\1/")

Un lindo y sencillo revestimiento que no deja rastro:

AJ
fuente