Estoy un poco sorprendido de que nadie haya mencionado esto todavía, pero puede usarlo readlink -f
para 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 -f
comando 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/dir
ARG
.
.
PATH
ARGA
/path/to/my/bin/dir
.
PATH
/path/to/my/bin/dir
PATH
Quizás lo más importante, el propósito principal de readlink
es, 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.14
en tu RUTA, bueno, está bien; podemos dejarlo como está. Pero, si /usr/lib/perl/5.14
no está ya en su PATH, llamamos readlink
y 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.2
en su RUTA y, nuevamente, debemos verificarlo para evitar agregarlo por PATH
segunda 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 readlink
tiene é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 readlink
falle, pero, como se discutió en Cómo recuperar la ruta absoluta de un archivo arbitrario desde OS X
y en otros lugares, readlink
es 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 -f
no parece funcionar en Mac OS X 10.11.6, pero realpath
funciona fuera de la caja ". Entonces, si está en un sistema que no tiene readlink
, o donde readlink -f
no 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 -d
prueba ( [ -d "$ARGA" ]
) probablemente sea realmente innecesaria. No puedo pensar en ningún escenario donde $ARG
sea un directorio y readlink
tenga éxito, pero $ARGA
no es un directorio. Simplemente copié y pegué la primera if
declaración para crear la tercera, y dejé la -d
prueba 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_profile
y .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 pathappend
comando, en lugar de mysql
? Y eso pathappend
no 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
}