¿Cómo agregar correctamente una ruta a PATH?

922

Me pregunto dónde se debe agregar una nueva ruta a la PATHvariable de entorno. Sé que esto se puede lograr editando .bashrc(por ejemplo), pero no está claro cómo hacerlo.

De esta manera:

export PATH=~/opt/bin:$PATH

¿o esto?

export PATH=$PATH:~/opt/bin
Paolo
fuente
printf '\ nPATH = $ PATH: "ruta de acceso para agregar" \ nexport PATH \ n' >> ~ / .bashrc
Sudoer
Si ya hay algunas rutas agregadas, por ejemplo PATH=$PATH:$HOME/.local/bin:$HOME/bin, se puede agregar otra separando con: eg PATH=$PATH:$HOME/.local/bin:$HOME/bin:/home/ec2-user/pear/bin.
Sandeepan Nath
2
¿Estas respuestas funcionan para todos los sabores de Linux?
Ungeheuer

Respuestas:

1035

Las cosas simples

PATH=$PATH:~/opt/bin

o

PATH=~/opt/bin:$PATH

dependiendo de si desea agregar ~/opt/binal final (para buscar todos los demás directorios, en caso de que haya un programa con el mismo nombre en varios directorios) o al principio (para buscar antes de todos los demás directorios).

Puede agregar varias entradas al mismo tiempo. PATH=$PATH:~/opt/bin:~/opt/node/bino variaciones en el orden funcionan bien. No coloque exportal comienzo de la línea ya que tiene complicaciones adicionales (consulte más abajo en "Notas sobre los depósitos que no sean bash").

Si PATHse compila por muchos componentes diferentes, puede terminar con entradas duplicadas. Consulte ¿Cómo agregar la ruta del directorio de inicio para que Unix descubra qué comando? y Eliminar entradas duplicadas de $ PATH con el comando awk para evitar agregar duplicados o eliminarlos.

Algunas distribuciones se colocan automáticamente ~/binen su RUTA si existe, por cierto.

Donde ponerlo

Ponga la línea de modificar PATHen ~/.profile, o ~/.bash_profilesi eso es lo que tiene.

Tenga en cuenta que ~/.bash_rcningún programa lo lee y ~/.bashrces el archivo de configuración de instancias interactivas de bash. No debe definir variables de entorno en ~/.bashrc. El lugar correcto para definir variables de entorno como PATHes ~/.profile(o ~/.bash_profilesi no le importan los shells que no sean bash). Vea ¿Cuál es la diferencia entre ellos y cuál debo usar?

No lo pongas /etc/environmento ~/.pam_environment: estos no son archivos de shell, no puedes usar sustituciones como $PATHallí. En estos archivos, solo puede anular una variable, no agregarla.

Posibles complicaciones en algunos scripts del sistema

No es necesario exportsi la variable ya está en el entorno: cualquier cambio en el valor de la variable se refleja en el entorno. PATH¹ es casi siempre en el entorno; todos los sistemas unix lo configuraron desde el principio (de hecho, generalmente en el primer proceso).

En el momento de iniciar sesión, puede confiar en PATHque ya está en el entorno y que ya contiene algunos directorios del sistema. Si estás escribiendo un guión que puede ser ejecutado temprana, mientras que la creación de algún tipo de entorno virtual, es posible que necesite para asegurarse de que PATHno está vacío y se exportan: si PATHtodavía está desactivada, entonces algo así PATH=$PATH:/some/directorysería ajustado PATHa :/some/directory, y el componente de vacío al principio significa el directorio actual (como .:/some/directory).

if [ -z "${PATH-}" ]; then export PATH=/usr/local/bin:/usr/bin:/bin; fi

Notas sobre conchas que no sean bash

En bash, ksh y zsh, exportes una sintaxis especial, y ambos PATH=~/opt/bin:$PATHy export PATH=~/opt/bin:$PATHhacer lo correcto, incluso. En otros shells de estilo Bourne / POSIX, como el guión (que se encuentra /bin/shen muchos sistemas), exportse analiza como un comando ordinario, lo que implica dos diferencias:

Entonces, en shells como el guión, se export PATH=~/opt/bin:$PATHestablece PATHen la cadena literal ~/opt/bin/:seguida del valor de PATHhasta el primer espacio. PATH=~/opt/bin:$PATH(una asignación simple) no requiere comillas y hace lo correcto. Si desea usar exporten un script portátil, necesita escribir export PATH="$HOME/opt/bin:$PATH", o PATH=~/opt/bin:$PATH; export PATH(o PATH=$HOME/opt/bin:$PATH; export PATHpara portabilidad incluso en el shell Bourne que no aceptó export var=valuey no hizo una expansión de tilde).

¹ Esto no era cierto en los proyectiles Bourne (como en el proyectil Bourne real, no en los proyectiles modernos de estilo POSIX), pero es muy poco probable que se encuentren con proyectiles tan viejos en estos días.

Gilles
fuente
Todavía no puedo entender la complicación con la exportación. ¿puedes por favor simplificarlo?
priojeet priyom
@priojeetpriyom Explicación simple: no necesitas export.
Gilles
Gracias por esta respuesta, perfectamente detallada. Usted dice " No debe definir variables de entorno en ~ / .bashrc ", pero desafortunadamente el 100% de los programas que he instalado en mi sistema que modifican la ruta (FZF y Rust's Cargo) modifican la ruta .bashrc. Supongo que porque FZF está escrito en Rust también está siguiendo el patrón de Rust.
icc97
84

De cualquier manera funciona, pero no hacen lo mismo: los elementos de PATHse verifican de izquierda a derecha. En su primer ejemplo, los ejecutables en ~/opt/bintendrán prioridad sobre los instalados, por ejemplo, en /usr/bin, que pueden o no ser lo que desea.

En particular, desde el punto de vista de la seguridad, es peligroso agregar rutas al frente, porque si alguien puede obtener acceso de escritura a la suya ~/opt/bin, puede poner, por ejemplo, una diferente lsallí, que probablemente usaría en su lugar. de /bin/lssin darse cuenta. Ahora imagina lo mismo para sshtu navegador o tu elección ... (Lo mismo se aplica al ponerlo en tu camino).

Ulrich Schwarz
fuente
66
Pero si desea tener su propia versión personalizada de ls, debe colocarla en un directorio antes /bin.
Barmar
16
o alias ls = myls
waltinator
37

Estoy confundido con la pregunta 2 (ya que se eliminó de la pregunta porque se debió a un problema no relacionado):

¿Cuál es una forma viable de agregar más rutas en diferentes líneas? Inicialmente pensé que esto podría hacer el truco:

export PATH=$PATH:~/opt/bin
export PATH=$PATH:~/opt/node/bin

pero no lo hace porque la segunda asignación no solo se agrega ~/opt/node/bin, sino también la totalidad PATHasignada anteriormente.

Esta es una posible solución alternativa:

export PATH=$PATH:~/opt/bin:~/opt/node/bin

pero para facilitar la lectura, preferiría tener una asignación para una ruta.

Si usted dice

PATH=~/opt/bin

eso es todo lo que estará en tu RUTA. RUTA es solo una variable de entorno, y si desea agregar a la RUTA, debe reconstruir la variable con exactamente el contenido que desea. Es decir, lo que da como ejemplo a la pregunta 2 es exactamente lo que quiere hacer, a menos que me esté perdiendo totalmente el punto de la pregunta.

Yo uso ambos formularios en mi código. Tengo un perfil genérico que instalo en cada máquina en la que trabajo que se ve así, para acomodar directorios que pueden faltar:

export PATH=/opt/bin:/usr/local/bin:/usr/contrib/bin:/bin:/usr/bin:/usr/sbin:/usr/bin/X11
# add optional items to the path
for bindir in $HOME/local/bin $HOME/bin; do
    if [ -d $bindir ]; then
        PATH=$PATH:${bindir}
    fi
done
Carl Cravens
fuente
2
Tienes razón sobre el ejemplo de la pregunta 2, funciona. Otro problema relacionado con la RUTA en mi sistema me confundió. Lo siento por eso.
Paolo
26

La forma a prueba de balas de anexar / anteponer

Hay muchas consideraciones involucradas en la elección de anexar versus anteponer. Muchos de ellos están cubiertos en otras respuestas, por lo que no los repetiré aquí.

Un punto importante es que, incluso si los scripts del sistema no usan esto (me pregunto por qué) * 1 , la forma a prueba de balas para agregar una ruta (p. Ej. $HOME/bin) A la variable de entorno PATH es

PATH="${PATH:+${PATH}:}$HOME/bin"

para anexar (en lugar de PATH="$PATH:$HOME/bin") y

PATH="$HOME/bin${PATH:+:${PATH}}"

para anteponer (en lugar de PATH="$HOME/bin:$PATH")

Esto evita el colon espurio $PATHinicial / final cuando está inicialmente vacío, lo que puede tener efectos secundarios no deseados y puede convertirse en una pesadilla , difícil de encontrar ( esta respuesta trata brevemente el caso en el awkcamino).

Explicación (de la expansión del parámetro Shell ):

${parameter:+word}

Si parameteres nulo o no establecido, nada se sustituye, de lo contrario, la expansión de wordse sustituye.

Por lo tanto, ${PATH:+${PATH}:}se expande a: 1) nada, si PATHes nulo o no establecido, 2) ${PATH}:, si PATHestá establecido.

Nota : Esto es para bash.


* 1 Acabo de descubrir que los scripts como devtoolset-6/enablerealmente usan esto,

$ cat /opt/rh/devtoolset-6/enable
# General environment variables
export PATH=/opt/rh/devtoolset-6/root/usr/bin${PATH:+:${PATH}}
...
sancho.s
fuente
24

Linux determina la ruta de búsqueda ejecutable con la $PATHvariable de entorno. Para agregar directorio / data / myscripts al comienzo de la $PATHvariable de entorno, use lo siguiente:

PATH=/data/myscripts:$PATH

Para agregar ese directorio al final de la ruta, use el siguiente comando:

PATH=$PATH:/data/myscripts

Pero lo anterior no es suficiente porque cuando establece una variable de entorno dentro de un script, ese cambio es efectivo solo dentro del script. Solo hay dos formas de evitar esta limitación:

  • Si dentro de la secuencia de comandos, exporta la variable de entorno, es efectiva dentro de cualquier programa llamado por la secuencia de comandos. Tenga en cuenta que no es efectivo dentro del programa que llamó al script.
  • Si el programa que llama al script lo hace mediante inclusión en lugar de llamar, cualquier cambio de entorno en el script es efectivo dentro del programa de llamada. Dicha inclusión se puede hacer con el comando punto o el comando fuente.

Ejemplos:

$HOME/myscript.sh
source $HOME/myscript.sh

La inclusión básicamente incorpora el guión "llamado" en el guión "llamado". Es como un #include en C. Por lo tanto, es efectivo dentro del script o programa "llamado". Pero, por supuesto, no es efectivo en ningún programa o script llamado por el programa de llamada. Para que sea efectivo en toda la cadena de llamadas, debe seguir la configuración de la variable de entorno con un comando de exportación.

Como ejemplo, el programa bash shell incorpora los contenidos del archivo .bash_profile por inclusión. Coloque las siguientes 2 líneas en .bash_profile:

PATH=$PATH:/data/myscripts
export PATH

efectivamente coloca esas 2 líneas de código en el programa bash. Entonces, dentro de bash, la variable $ PATH incluye $HOME/myscript.sh, y debido a la declaración de exportación, cualquier programa llamado por bash tiene la $PATHvariable alterada . Y dado que bash llama a cualquier programa que ejecute desde un indicador bash, la nueva ruta está en vigor para todo lo que ejecute desde el indicador bash.

La conclusión es que para agregar un nuevo directorio a la ruta, debe agregar o anteponer el directorio a la variable de entorno $ PATH dentro de un script incluido en el shell, y debe exportar la $PATHvariable de entorno.

Más información aquí.

Steve Brown
fuente
19

Desde hace algún tiempo he mantenido conmigo dos funciones pathaddy pathrmque ayudan en la adición de elementos a la ruta sin la necesidad de preocuparse por las duplicaciones.

pathaddtoma un argumento de ruta única y un afterargumento opcional que, si se proporciona, se agregará al PATHcaso anterior.

En casi todas las situaciones, si está agregando a la ruta, es probable que desee anular cualquier cosa que ya esté en la ruta, por lo que opto por anteponer por defecto.

pathadd() {
    newelement=${1%/}
    if [ -d "$1" ] && ! echo $PATH | grep -E -q "(^|:)$newelement($|:)" ; then
        if [ "$2" = "after" ] ; then
            PATH="$PATH:$newelement"
        else
            PATH="$newelement:$PATH"
        fi
    fi
}

pathrm() {
    PATH="$(echo $PATH | sed -e "s;\(^\|:\)${1%/}\(:\|\$\);\1\2;g" -e 's;^:\|:$;;g' -e 's;::;:;g')"
}

Ponga esto en cualquier script que desee alterar el entorno PATH y ahora puede hacerlo.

pathadd "/foo/bar"
pathadd "/baz/bat" after
export PATH

Le garantizamos que no agregará a la ruta si ya está allí. Si ahora quieres asegurarte /baz/bates al principio.

pathrm "/baz/bat"
pathadd "/baz/bat"
export PATH

Ahora cualquier camino se puede mover al frente si ya está en el camino sin duplicarlo.

Brett Ryan
fuente
Enfoque más limpio y relacionado para verificar la presencia de un directorio en su RUTA: unix.stackexchange.com/a/32054/135943
Wildcard
9

No puedo hablar por otras distribuciones, pero Ubuntu tiene un archivo, / etc / environment, que es la ruta de búsqueda predeterminada para todos los usuarios. Como mi computadora solo la uso yo, pongo los directorios que quiero en mi camino allí, a menos que sea una adición temporal que coloque en un script.

Jim Bradley
fuente
6

Hay algunas situaciones en las que su uso PATH=/a/b:$PATHpodría considerarse la forma "incorrecta" de agregar una ruta a PATH:

  1. Agregar una ruta que en realidad no es un directorio.
  2. Agregar una ruta que ya está PATHen la misma forma.
  3. Agregar una ruta relativa (ya que el directorio real buscado cambiará a medida que cambie el directorio de trabajo actual).
  4. Agregar una ruta que ya está en PATHuna forma diferente (es decir, un alias debido al uso de enlaces simbólicos o ..).
  5. Si evita hacer 4, no mueve la ruta al frente de PATHcuando está destinado a anular otras entradas PATH.

Esta función (solo Bash) hace lo "correcto" en las situaciones anteriores (con una excepción, ver más abajo), devuelve códigos de error e imprime mensajes agradables para humanos. Los códigos y mensajes de error se pueden deshabilitar cuando no se desean.

prepath() {
    local usage="\
Usage: prepath [-f] [-n] [-q] DIR
  -f Force dir to front of path even if already in path
  -n Nonexistent dirs do not return error status
  -q Quiet mode"

    local tofront=false errcode=1 qecho=echo
    while true; do case "$1" in
        -f)     tofront=true;       shift;;
        -n)     errcode=0;          shift;;
        -q)     qecho=':';          shift;;
        *)      break;;
    esac; done
    # Bad params always produce message and error code
    [[ -z $1 ]] && { echo 1>&2 "$usage"; return 1; }

    [[ -d $1 ]] || { $qecho 1>&2 "$1 is not a directory."; return $errcode; }
    dir="$(command cd "$1"; pwd -P)"
    if [[ :$PATH: =~ :$dir: ]]; then
        $tofront || { $qecho 1>&2 "$dir already in path."; return 0; }
        PATH="${PATH#$dir:}"        # remove if at start
        PATH="${PATH%:$dir}"        # remove if at end
        PATH="${PATH//:$dir:/:}"    # remove if in middle
    fi
    PATH="$dir:$PATH"
}

La excepción es que esta función no canoniza las rutas agregadas a PATHtravés de otros medios, por lo que si hay un alias no canónico para una ruta PATH, esto agregará un duplicado. Intentar PATHcanonizar las rutas que ya están en una propuesta incierta ya que una ruta relativa tiene un significado obvio cuando se pasa a, prepathpero cuando ya se encuentra en la ruta no se sabe cuál era el directorio de trabajo actual cuando se agregó.

Curt J. Sampson
fuente
con respecto a las rutas relativas: ¿qué pasa con tener un interruptor '-r', que agregaría la ruta sin hacerla absoluta primero, y que también la buscaría como absoluta antes de agregarla? Si este fuera un script, uno podría usarlo en otros shells. ¿Hay algún beneficio de tenerlo como una función? buen código!
hoijui
1
@hoijui Tiene que ser una función porque está modificando el entorno actual. Si se tratara de una secuencia de comandos, modificaría el entorno del subproceso que ejecuta la secuencia de comandos y, cuando salga de la secuencia de comandos, tendrá el mismo $PATHque tenía antes. En cuanto a -r, no, creo que las rutas relativas en $PATHson demasiado poco confiables y extrañas (¡tu ruta cambia cada vez que tú cd!) Para querer apoyar algo así en una herramienta general.
Curt J. Sampson
5

Para mí (en Mac OS X 10.9.5), agregar el nombre de la ruta (por ejemplo /mypathname) al archivo /etc/pathsfuncionó muy bien.

Antes de editar, echo $PATHdevuelve:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin

Después de editar /etc/pathsy reiniciar el shell, se agrega la variable $ PATH /pathname. De hecho, echo $PATHdevuelve:

/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/mypathname

Lo que sucedió es que /mypathnamese ha agregado a la $PATHvariable.

faelx
fuente
3
Es mejor agregar un archivo al directorio /etc/paths.d que editar el archivo / etc / paths en sí.
rbrewer
4

Para agregar una nueva ruta a la PATHvariable de entorno:

export PATH=$PATH:/new-path/

Para que este cambio se aplicará a todos los depósitos se abre, añadirlo al archivo que el shell la fuente cuando se invoca. En diferentes shells esto puede ser:

  • Bash Shell: ~ / .bash_profile, ~ / .bashrc o perfil
  • Korn Shell: ~ / .kshrc o .profile
  • Z Shell: ~ / .zshrc o .zprofile

p.ej

# export PATH=$PATH:/root/learning/bin/
# source ~/.bashrc
# echo $PATH

Puede ver la ruta proporcionada en la salida anterior.

Amit24x7
fuente
4

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
1
-bash: awk: no existe tal archivo o directorio -bash: sed: no existe dicho archivo o directorio
davidcondrey
1
@davidcondrey - awk y sed son comandos externos muy comunes. Esta respuesta proporciona una manera pura de lograr lo mismo, por lo que funciona incluso en casos en que awk y / o sed no están presentes (¡o sus respectivos directorios no están en el camino!)
sancho.s