Je suis un peu surpris que personne n'en ait encore parlé, mais vous pouvez utiliser readlink -f
pour convertir des chemins relatifs en chemins absolus et les ajouter au PATH en tant que tels.
Par exemple, pour améliorer la réponse de Guillaume Perrault-Archambault,
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
PATH="${PATH:+"$PATH:"}$ARG"
fi
done
}
devient
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. L'essentiel - à quoi sert-il?
La readlink -f
commande convertira (entre autres choses) un chemin relatif en un chemin absolu. Cela vous permet de faire quelque chose comme
$ cd / path / to / my / bin / dir
$ pathappend .
$ echo "$ PATH"
<your_old_path> : / path / to / my / bin / dir
2. Pourquoi testons-nous deux fois sur PATH?
Eh bien, considérons l'exemple ci-dessus. Si l'utilisateur dit à
partir du répertoire une deuxième fois,
sera . Bien sûr, ne sera pas présent dans . Mais alors sera mis à
(l'équivalent absolu de chemin de ), qui est déjà dans . Nous devons donc éviter d’ajouter à une deuxième fois.pathappend .
/path/to/my/bin/dir
ARG
.
.
PATH
ARGA
/path/to/my/bin/dir
.
PATH
/path/to/my/bin/dir
PATH
Peut-être plus important encore, l'objectif principal de readlink
, comme son nom l'indique, est d'examiner un lien symbolique et de lire le chemin qu'il contient (c.-à-d. Qu'il pointe vers). Par exemple:
$ 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
Maintenant, si vous dites pathappend /usr/lib/perl/5.14
, et vous avez déjà /usr/lib/perl/5.14
dans votre CHEMIN, eh bien, c'est bien; nous pouvons simplement le laisser tel quel. Mais, si ce /usr/lib/perl/5.14
n'est pas déjà dans votre PATH, nous appelons readlink
et obtenons ARGA
= /usr/lib/perl/5.14.2
, puis nous ajoutons cela à PATH
. Mais attendez une minute - si vous avez déjà dit pathappend /usr/lib/perl/5.14
, alors vous avez déjà /usr/lib/perl/5.14.2
dans votre PATH, et, encore une fois, nous devons vérifier cela pour éviter de l'ajouter PATH
une seconde fois.
3. Quel est le problème if ARGA=$(readlink -f "$ARG")
?
En cas de doute, cette ligne teste si l'opération readlink
réussit. Ceci est juste une bonne pratique de programmation défensive. Si nous allons utiliser le résultat de la commande m
dans le cadre de la commande n (où m < n ), il est prudent de vérifier si la commande m a échoué et de le gérer d'une manière ou d'une autre. Je ne pense pas que cela risque d’ readlink
échouer - mais, comme indiqué dans Comment récupérer le chemin absolu d’un fichier arbitraire sous OS X
et ailleurs, il readlink
s’agit d’une invention de GNU. Comme il n'est pas spécifié dans POSIX, sa disponibilité dans Mac OS, Solaris et d'autres Unix non Linux est discutable. (En fait, je viens de lire un commentaire qui dit “readlink -f
ne semble pas fonctionner sous Mac OS X 10.11.6, mais realpath
fonctionne " clé en main". Ainsi, si vous utilisez un système qui ne fonctionne pas readlink
ou readlink -f
qui ne fonctionne pas, vous pourrez peut-être le modifier. script à utiliser realpath
.) En installant un filet de sécurité, nous rendons notre code un peu plus portable.
Bien sûr, si vous êtes sur un système qui n'a pas readlink
(ou realpath
), vous ne voudrez pas le faire .pathappend .
Le deuxième -d
test ( [ -d "$ARGA" ]
) est probablement probablement inutile. Je ne peux pas penser à un scénario où $ARG
est un répertoire et readlink
réussit, mais $ARGA
n'est pas un répertoire. Je viens de copier-coller la première if
déclaration pour créer la troisième et j'ai laissé le -d
test là-bas par paresse.
4. Autres commentaires?
Ouais. Comme beaucoup d'autres réponses ici, celle-ci vérifie si chaque argument est un répertoire, le traite si c'est le cas et l'ignore s'il ne l'est pas. Cela peut être (ou non) adéquat si vous utilisez pathappend
uniquement des .
fichiers “ ” (comme .bash_profile
et .bashrc
) et d’autres scripts. Mais, comme le montre cette réponse (ci-dessus), il est parfaitement possible de l’utiliser de manière interactive. Vous serez très perplexe si vous le faites
$ pathappend /usr/local/nysql/bin
$ mysql
-bash: mysql: command not found
Avez-vous remarqué que j'ai dit nysql
dans le pathappend
commandement, plutôt que mysql
? Et cela pathappend
n'a rien dit; il a juste silencieusement ignoré l'argument incorrect?
Comme je l'ai dit plus haut, il est recommandé de gérer les erreurs. Voici un exemple:
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
}