Me gustaría una manera de agregar cosas a $ PATH, en todo el sistema o para un usuario individual, sin potencialmente agregar la misma ruta varias veces.
Una razón para querer hacer esto es para que se puedan hacer adiciones .bashrc, lo que no requiere un inicio de sesión, y también es más útil en sistemas que usan (por ejemplo) lightdm, que nunca llama .profile.
Soy consciente de las preguntas que tratan sobre cómo limpiar duplicados de $ PATH, pero no quiero eliminar duplicados . Me gustaría una forma de agregar rutas solo si aún no están presentes.

Respuestas:
Supongamos que la nueva ruta que queremos agregar es:
Luego, usando cualquier shell POSIX, podemos probar para ver si
newya está en la ruta y agregarlo si no lo está:Tenga en cuenta el uso de dos puntos. Sin los dos puntos, podríamos pensar que, por ejemplo,
new=/binya estaba en el camino porque el patrón coincidía/usr/bin. Mientras que las RUTA normalmente tienen muchos elementos, también se manejan los casos especiales de cero y un elemento en la RUTA. El caso de la PATH inicialmente no tener elementos (siendo vacío) es manejado por el uso de${PATH:=$new}que asignaPATHa$newsi está vacío. Establecer valores predeterminados para los parámetros de esta manera es una característica de todos los shells POSIX: consulte la sección 2.6.2 de los documentos POSIX ).Una función invocable
Por conveniencia, el código anterior se puede poner en una función. Esta función se puede definir en la línea de comando o, para tenerla disponible permanentemente, ponerla en el script de inicialización de su shell (para usuarios bash, eso sería
~/.bashrc):Para usar esta función de actualización de ruta para agregar un directorio a la RUTA actual:
fuente
PATHestá vacío, esto agregará una entrada vacía (es decir, el directorio actual) alPATH. Creo que necesitas otro caso.case. Solo hazlocase "${PATH:=$new}". Vea mi propia respuesta para fallos similares.Cree un archivo
/etc/profile.dllamado, por ejemplo,mypath.sh(o lo que quiera). Si está utilizando lightdm, asegúrese de que sea viable o de lo contrario utilice/etc/bashrco un archivo procedente de la misma. Agregue a eso las siguientes funciones:Las cosas al comienzo de (antes) $ PATH tienen prioridad sobre lo que sigue, y por el contrario, las cosas al final (agregadas) serán reemplazadas por lo que viene antes. Esto significa que si su $ PATH es
/usr/local/bin:/usr/biny hay un ejecutablegotchaen ambos directorios, el de adentro/usr/local/binse usará por defecto.Ahora puede, en este mismo archivo, en otro archivo de configuración de shell o desde la línea de comandos, usar:
Si esto está en a
.bashrc, evitará que el valor aparezca más de una vez cuando inicie un nuevo shell. Hay una limitación en que si desea agregar algo que se antepuso (es decir, mover una ruta dentro de $ PATH) o viceversa, tendrá que hacerlo usted mismo.fuente
$PATHconIFS=:finalmente es más flexible quecase.case, IMO. Me imagino que tambiénawkpodría usarse aquí.gawkpodría asignar directamente$PATH.Puedes hacerlo de esta manera:
Nota: si crea RUTA a partir de otras variables, verifique que no estén vacías, ya que muchos shells interpretan "" me gusta "". .
fuente
-qPOSIX requiere grep, pero no sé si eso significa que todavía hay algunos greps (no POSIX) que no lo tienen./my/binLa parte importante del código es verificar si
PATHcontiene una ruta específica:Es decir, asegúrese de que cada ruta en
PATHesté delimitada en ambos lados por elPATHseparador (:), luego verifique (-q) si la cadena literal (-F) que consiste en unPATHseparador, su ruta y otroPATHseparador existe allí. Si no es así, puede agregar la ruta de forma segura:Esto debería ser compatible con POSIX y debería funcionar con cualquier ruta que no contenga un carácter de nueva línea. Es más complejo si desea que funcione con rutas que contengan nueva línea mientras sea compatible con POSIX, pero si tiene un
grepsoporte-zque pueda usar, puede usarlo.fuente
He estado llevando esta pequeña función conmigo en varios
~/.profilearchivos durante años. Yo creo que fue escrito por el administrador de sistemas en un laboratorio que solía trabajar en, pero no estoy seguro. De todos modos, es similar al enfoque de Goldilock pero ligeramente diferente:Entonces, para agregar un nuevo directorio al comienzo de
PATH:y hasta el final:
fuente
/bin/grep->grepACTUALIZAR:
Me di cuenta de que su propia respuesta tenía una función separada cada una para agregar o anteponer al
$PATH. Me gustó la idea. Así que agregué un pequeño manejo de argumentos. También lo_separé correctamente :SALIDA:
De forma predeterminada,
-Adependerá de$PATH, pero puede modificar este comportamiento para que se-Pagregue agregando un-Plugar en su lista de argumentos. Puede volver a-Aponerlo en espera entregándolo-Anuevamente.EVALO SEGURO
En la mayoría de los casos, recomiendo que las personas eviten el uso de
eval. Pero esto, creo, se destaca como un ejemplo de su uso para bien. En este caso, la única declaración queevalpuede ver esP=oA=. Los valores de sus argumentos se prueban estrictamente antes de que se llame. Esto es para lo queevalsirve.Esto aceptará tantos argumentos como le des y agregará cada uno
$PATHsolo una vez y solo si aún no está en$PATH. Solo utiliza el script de shell POSIX totalmente portátil, se basa solo en los shell incorporados y es muy rápido.fuente
_viene la idea de que las funciones de prefijo de shell las hacen "espaciadas correctamente"? En otros idiomas, generalmente indicaría una función global interna (es decir, una que debe ser global, pero no está destinada a ser utilizada externamente como parte de una API). Mis nombres ciertamente no son buenas opciones, pero me parece que el solo uso_no resuelve los problemas de colisión en absoluto; sería mejor agregar un espacio de nombres real, por ejemplo.mikeserv_path_assign()._entonces necesita cambiar los administradores de paquetes. En cualquier caso, esto, esencialmente, es solo una "función global, interna" : es global para cada shell invocado desde el shell en el que se declara, y es solo un poco de script de lenguaje interpretado que cuelga en la memoria del intérprete . unix.stackexchange.com/questions/120528/…unset a(o equivalente) al final del perfil?¡Mirad! La función de 12 líneas de fuerza industrial ... técnicamente bash y zsh-portable que adora tu script de inicio
~/.bashrco~/.zshrcde elección:Prepárate para la gloria instantánea. Entonces, en lugar de hacer esto y deseando lo mejor:
Haga esto en su lugar y tenga la garantía de obtener lo mejor, ya sea que realmente quiera eso o no:
Muy bien, defina "Mejor".
Anexar y anteponer con seguridad a la corriente
${PATH}no es el asunto trivial que comúnmente se supone que es. Si bien son convenientes y aparentemente razonables, las frases ingeniosas del formularioexport PATH=$PATH:~/opt/bininvitan a complicaciones diabólicas con:Nombres de directorio relativos accidentalmente (por ejemplo,
export PATH=$PATH:opt/bin). Si bienbashy enzshsilencio aceptan e ignoran en su mayoría los nombres de directorios relativos en la mayoría de los casos, los nombres de directorios relativos con el prefijo unohot(y posiblemente otros caracteres nefastos) hacen que ambos se mutilen vergonzosamente por Harakiri, la obra maestra seminal de 1962 de Masaki Kobayashi :Accidentalmente nombres de directorio duplicados. Si bien los
${PATH}nombres de directorio duplicados son en gran medida inocuos, también son indeseados, engorrosos, ligeramente ineficientes, impiden la depuración y promueven el desgaste de la unidad, como esta respuesta. Mientras que los SSD de estilo NAND son ( por supuesto ) inmunes al desgaste de lectura, los HDD no lo son. El acceso innecesario al sistema de archivos en cada intento de comando implica un desgaste innecesario del cabezal de lectura al mismo tempo. Los duplicados son particularmente untuosos cuando se invocan proyectiles anidados en subprocesos anidados, momento en el cual las frases ingenuas aparentemente inocuasexport PATH=$PATH:~/watexplotan rápidamente en el Séptimo Círculo del${PATH}InfiernoPATH=/usr/local/bin:/usr/bin:/bin:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat:/home/leycec/wat. Solo Beelzebubba puede ayudarlo si luego agrega nombres de directorio adicionales. (No dejes que esto le pase a tus preciosos hijos. )${PATH}nombres de directorio faltantes son en gran medida inocuos, también suelen ser no deseados, engorrosos, ligeramente ineficientes, impiden la depuración y promueven el desgaste de la unidad.Ergo, automatización amigable como la función de shell definida anteriormente. Debemos salvarnos de nosotros mismos.
Pero ... ¿Por qué "+ path.append ()"? ¿Por qué no simplemente append_path ()?
Para de desambiguación (por ejemplo, con comandos externos en las actuales
${PATH}funciones de shell o del sistema definida en otra parte), funciones de shell definidos por el usuario son idealmente el prefijo o sufijo única subseries soportados porbashyzshpero prohibidos de otro modo para nombres base comando estándar - como, por ejemplo,+.Oye. Funciona. No me juzgues
Pero ... ¿Por qué "+ path.append ()"? ¿Por qué no "+ path.prepend ()"?
Debido a que agregar a la corriente
${PATH}es más seguro que anteponer a la corriente${PATH}, todas las cosas son iguales, lo que nunca son. Anular comandos de todo el sistema con comandos específicos del usuario puede ser insalubre en el mejor de los casos y loco en el peor En Linux, por ejemplo, las aplicaciones posteriores comúnmente esperan las variantes de comandos GNU coreutils en lugar de las derivadas o alternativas no estándar personalizadas.Dicho esto, absolutamente hay casos de uso válidos para hacerlo. Definir la
+path.prepend()función equivalente es trivial. Sans prolix nebulosity, por su cordura compartida:Pero ... ¿por qué no Gilles?
La respuesta aceptada de Gilles en otra parte es impresionantemente óptima en el caso general como un "agregado idempotente agnóstico de caparazón" . En el caso común de
bashyzshcon no hay enlaces simbólicos indeseables, sin embargo, la penalización de rendimiento requerido para ello entristece la arrocera de Gentoo en mí. Incluso en presencia de enlaces simbólicos indeseables, es discutible si la bifurcación de un subshell poradd_to_PATH()argumento vale la inserción potencial de duplicados de enlaces simbólicos.Para casos de uso estrictos que exigen que se eliminen incluso los duplicados de enlaces simbólicos, esta
zshvariante específica lo hace a través de builtins eficientes en lugar de tenedores ineficientes:Tenga en cuenta el
*":${dirname:A}:"*más que*":${dirname}:"*el original.:Aes unzshismos maravilloso tristemente ausente debajo de la mayoría de los otros caparazones, incluidobash. Para citarman zshexpn:No más preguntas.
De nada. Disfruta del bombardeo seguro. Ahora te lo mereces.
fuente
Aquí está mi versión de estilo de programación funcional.
*PATHvariable delimitada por dos puntos , no soloPATH.También digno de mención:
exporting; eso le queda a la persona que llama (ver ejemplos)bash; sin bifurcaciónpath_add () { # $ 1: Elemento para asegurar que está en la cadena de ruta dada exactamente una vez # $ 2: valor de cadena de ruta existente ("$ PATH", no "PATH") # $ 3 (opcional, cualquier cosa): si se proporciona, agregue $ 1; de lo contrario, anteponer # # # Ejemplos: # $ export PATH = $ (path_add '/ opt / bin' "$ PATH") # $ CDPATH = $ (path_add '/ Music' "$ CDPATH" at_end) local -r already_present = "(^ |:) $ {1} ($ | :)" if [["$ 2" = ~ $ ya_presenta]]; luego echo "$ 2" elif [[$ # == 3]]; luego echo "$ {2}: $ {1}" más echo "$ {1}: $ {2}" fi }fuente
Este script le permite agregar al final de
$PATH:O agregue al comienzo de
$PATH:fuente