Sono un po 'sorpreso che nessuno lo abbia ancora menzionato, ma puoi usarlo readlink -f
per convertire percorsi relativi in percorsi assoluti e aggiungerli al PERCORSO in quanto tale.
Ad esempio, per migliorare la risposta di Guillaume Perrault-Archambault,
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
PATH="${PATH:+"$PATH:"}$ARG"
fi
done
}
diventa
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. Le basi - A cosa serve questo?
Il readlink -f
comando convertirà (tra le altre cose) un percorso relativo in un percorso assoluto. Questo ti permette di fare qualcosa del genere
$ cd / path / to / my / bin / dir
$ pathappend .
$ echo "$ PATH"
<your_old_path> : / path / to / my / bin / dir
2. Perché testiamo per essere in PATH due volte?
Bene, considera l'esempio sopra. Se l'utente dice
dalla directory una seconda volta,
sarà . Certo, non sarà presente in . Ma poi sarà impostato su
(l'equivalente del percorso assoluto di ), che è già in . Quindi abbiamo bisogno di evitare di aggiungere ad una seconda volta.pathappend .
/path/to/my/bin/dir
ARG
.
.
PATH
ARGA
/path/to/my/bin/dir
.
PATH
/path/to/my/bin/dir
PATH
Forse ancora più importante, lo scopo principale di readlink
è, come suggerisce il nome, guardare un link simbolico e leggere il percorso che contiene (cioè, punta a). Per esempio:
$ 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
Ora, se dici pathappend /usr/lib/perl/5.14
, e hai già /usr/lib/perl/5.14
nel tuo PERCORSO, bene, va bene; possiamo lasciarlo così com'è. Ma, se /usr/lib/perl/5.14
non è già nel PATH, che noi chiamiamo readlink
e otteniamo ARGA
= /usr/lib/perl/5.14.2
, e poi aggiungiamo che a PATH
. Ma aspetta un minuto - se hai già detto pathappend /usr/lib/perl/5.14
, allora hai già /usr/lib/perl/5.14.2
nel tuo PERCORSO e, ancora una volta, dobbiamo controllarlo per evitare di aggiungerlo PATH
una seconda volta.
3. Qual è il if ARGA=$(readlink -f "$ARG")
problema con ?
Nel caso in cui non sia chiaro, questa riga verifica se ha readlink
esito positivo. Questa è solo una buona pratica di programmazione difensiva. Se useremo l'output del comando m
come parte del comando n (dove m < n ), è prudente verificare se il comando m non è riuscito e gestirlo in qualche modo. Non credo che probabilmente readlink
fallirà, ma, come discusso in Come recuperare il percorso assoluto di un file arbitrario da OS X
e altrove, readlink
è un'invenzione GNU. Non è specificato in POSIX, quindi la sua disponibilità in Mac OS, Solaris e altri Unix non Linux è discutibile. (In effetti, ho appena letto un commento che dice "readlink -f
non sembra funzionare su Mac OS X 10.11.6, ma realpath
funziona immediatamente . ”Quindi, se utilizzi un sistema che non ha readlink
o dove readlink -f
non funziona, potresti essere in grado di modificarlo script da usare realpath
.) Installando una rete di sicurezza, rendiamo il nostro codice un po 'più portabile.
Naturalmente, se utilizzi un sistema che non ha readlink
(o realpath
), non vorrai farlo .pathappend .
Il secondo -d
test ( [ -d "$ARGA" ]
) è davvero probabilmente non necessario. Non riesco a pensare a nessuno scenario in cui $ARG
una directory ha readlink
esito positivo, ma $ARGA
non è una directory. Ho appena copiato e incollato la prima if
istruzione per creare la terza e ho lasciato -d
lì il test per pigrizia.
4. Altri commenti?
Si. Come molte altre risposte qui, questa verifica se ogni argomento è una directory, lo elabora se lo è e lo ignora se non lo è. Questo può (o potrebbe non essere) adeguato se si utilizza pathappend
solo in " .
" file (come .bash_profile
e .bashrc
) e altri script. Ma, come ha mostrato questa risposta (sopra), è perfettamente fattibile utilizzarla in modo interattivo. Sarai molto perplesso se lo fai
$ pathappend /usr/local/nysql/bin
$ mysql
-bash: mysql: command not found
Hai notato che ho detto nysql
nel pathappend
comando, piuttosto che mysql
? E questo pathappend
non ha detto nulla; ha semplicemente ignorato in silenzio l'argomento errato?
Come ho detto sopra, è buona norma gestire gli errori. Ecco un esempio:
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
}