Je suis un peu surpris que personne n'en ait encore parlé, mais vous pouvez utiliser readlink -fpour 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 -fcommande 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/dirARG..PATHARGA/path/to/my/bin/dir.PATH/path/to/my/bin/dirPATH
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.14dans votre CHEMIN, eh bien, c'est bien; nous pouvons simplement le laisser tel quel. Mais, si ce /usr/lib/perl/5.14n'est pas déjà dans votre PATH, nous appelons readlinket 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.2dans votre PATH, et, encore une fois, nous devons vérifier cela pour éviter de l'ajouter PATHune seconde fois.
3. Quel est le problème if ARGA=$(readlink -f "$ARG")?
En cas de doute, cette ligne teste si l'opération readlinkré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 readlinks’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 -fne semble pas fonctionner sous Mac OS X 10.11.6, mais realpathfonctionne " clé en main". Ainsi, si vous utilisez un système qui ne fonctionne pas readlinkou readlink -fqui 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 -dtest ( [ -d "$ARGA" ]) est probablement probablement inutile. Je ne peux pas penser à un scénario où $ARGest un répertoire et readlinkréussit, mais $ARGAn'est pas un répertoire. Je viens de copier-coller la première ifdéclaration pour créer la troisième et j'ai laissé le -dtest 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_profileet .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 pathappendcommandement, plutôt que mysql? Et cela pathappendn'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
}