Sono un po 'sorpreso che nessuno lo abbia ancora menzionato, ma puoi usarlo readlink -fper 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 -fcomando 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/dirARG..PATHARGA/path/to/my/bin/dir.PATH/path/to/my/bin/dirPATH
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.14nel tuo PERCORSO, bene, va bene; possiamo lasciarlo così com'è. Ma, se /usr/lib/perl/5.14non è già nel PATH, che noi chiamiamo readlinke 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.2nel tuo PERCORSO e, ancora una volta, dobbiamo controllarlo per evitare di aggiungerlo PATHuna seconda volta.
3. Qual è il if ARGA=$(readlink -f "$ARG")problema con ?
Nel caso in cui non sia chiaro, questa riga verifica se ha readlinkesito 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 readlinkfallirà, 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 -fnon sembra funzionare su Mac OS X 10.11.6, ma realpathfunziona immediatamente . ”Quindi, se utilizzi un sistema che non ha readlinko dove readlink -fnon 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 -dtest ( [ -d "$ARGA" ]) è davvero probabilmente non necessario. Non riesco a pensare a nessuno scenario in cui $ARGuna directory ha readlinkesito positivo, ma $ARGAnon è una directory. Ho appena copiato e incollato la prima ifistruzione per creare la terza e ho lasciato -dlì 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_profilee .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 pathappendcomando, piuttosto che mysql? E questo pathappendnon 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
}