Estoy un poco sorprendido de que nadie haya mencionado esto todavía, pero puede usarlo readlink -fpara convertir rutas relativas en rutas absolutas y agregarlas a la RUTA como tal.
Por ejemplo, para mejorar la respuesta de Guillaume Perrault-Archambault,
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
PATH="${PATH:+"$PATH:"}$ARG"
fi
done
}
se convierte
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]
then
if ARGA=$(readlink -f "$ARG") #notice me
then
if [ -d "$ARGA" ] && [[ ":$PATH:" != *":$ARGA:"* ]]
then
PATH="${PATH:+"$PATH:"}$ARGA"
fi
else
PATH="${PATH:+"$PATH:"}$ARG"
fi
fi
done
}
1. Lo básico: ¿de qué sirve esto?
El readlink -fcomando convertirá (entre otras cosas) una ruta relativa en una ruta absoluta. Esto te permite hacer algo como
$ cd / ruta / a / mi / bin / dir
$ pathappend .
$ echo "$ PATH"
<your_old_path> : / path / to / my / bin / dir
2. ¿Por qué hacemos pruebas para estar en PATH dos veces?
Bueno, considere el ejemplo anterior. Si el usuario dice
desde el directorio por segunda vez,
será . Por supuesto, no estará presente en . Pero luego se establecerá en
(el equivalente de ruta absoluta de ), que ya está en . Por lo tanto, debemos evitar agregar a una segunda vez.pathappend ./path/to/my/bin/dirARG..PATHARGA/path/to/my/bin/dir.PATH/path/to/my/bin/dirPATH
Quizás lo más importante, el propósito principal de readlinkes, como su nombre lo indica, mirar un enlace simbólico y leer el nombre de ruta que contiene (es decir, apunta a). Por ejemplo:
$ ls -ld /usr/lib/perl/5.14
-rwxrwxrwx 1 root root Sep 3 2015 /usr/lib/perl/5.14 -> 5.14.2
$ readlink /usr/lib/perl/5.14
5.14.2
$ readlink -f /usr/lib/perl/5.14
/usr/lib/perl/5.14.2
Ahora, si dices pathappend /usr/lib/perl/5.14, y ya tienes /usr/lib/perl/5.14en tu RUTA, bueno, está bien; podemos dejarlo como está. Pero, si /usr/lib/perl/5.14no está ya en su PATH, llamamos readlinky nos ARGA= /usr/lib/perl/5.14.2, y luego añadimos que a PATH. Pero espere un minuto: si ya lo dijo pathappend /usr/lib/perl/5.14, ya lo tiene /usr/lib/perl/5.14.2en su RUTA y, nuevamente, debemos verificarlo para evitar agregarlo por PATHsegunda vez.
3. ¿Cuál es el trato con if ARGA=$(readlink -f "$ARG")?
En caso de que no esté claro, esta línea prueba si readlinktiene éxito. Esto es simplemente una buena práctica de programación defensiva. Si vamos a utilizar la salida del comando m
como parte del comando n (donde m < n ), es prudente verificar si el comando m falló y manejarlo de alguna manera. No creo que sea probable que readlinkfalle, pero, como se discutió en Cómo recuperar la ruta absoluta de un archivo arbitrario desde OS X
y en otros lugares, readlinkes una invención de GNU. No se especifica en POSIX, por lo que su disponibilidad en Mac OS, Solaris y otros Unix no Linux es cuestionable. (De hecho, acabo de leer un comentario que dice "readlink -fno parece funcionar en Mac OS X 10.11.6, pero realpathfunciona fuera de la caja ". Entonces, si está en un sistema que no tiene readlink, o donde readlink -fno funciona, puede modificar esto script para usar realpath.) Al instalar una red de seguridad, hacemos que nuestro código sea algo más portátil.
Por supuesto, si está en un sistema que no tiene readlink(o realpath), no querrá hacerlo .pathappend .
La segunda -dprueba ( [ -d "$ARGA" ]) probablemente sea realmente innecesaria. No puedo pensar en ningún escenario donde $ARGsea un directorio y readlinktenga éxito, pero $ARGAno es un directorio. Simplemente copié y pegué la primera ifdeclaración para crear la tercera, y dejé la -dprueba allí por flojera.
4. ¿Algún otro comentario?
Sí. Como muchas de las otras respuestas aquí, esta prueba si cada argumento es un directorio, lo procesa si lo es, y lo ignora si no lo es. Esto puede (o no) ser adecuado si está utilizando pathappend
solo en " ." archivos (como .bash_profiley .bashrc) y otros scripts. Pero, como mostró esta respuesta (arriba), es perfectamente factible usarlo de forma interactiva. Estarás muy perplejo si lo haces
$ pathappend /usr/local/nysql/bin
$ mysql
-bash: mysql: command not found
¿Te diste cuenta de que dije nysql
en el pathappendcomando, en lugar de mysql? Y eso pathappendno dijo nada; ¿simplemente ignoró en silencio el argumento incorrecto?
Como dije anteriormente, es una buena práctica manejar los errores. Aquí hay un ejemplo:
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ]
then
if [[ ":$PATH:" != *":$ARG:"* ]]
then
if ARGA=$(readlink -f "$ARG") #notice me
then
if [[ ":$PATH:" != *":$ARGA:"* ]]
then
PATH="${PATH:+"$PATH:"}$ARGA"
fi
else
PATH="${PATH:+"$PATH:"}$ARG"
fi
fi
else
printf "Error: %s is not a directory.\n" "$ARG" >&2
fi
done
}