Ich bin ein bisschen überrascht, dass dies noch niemand erwähnt hat, aber Sie können readlink -f
relative Pfade in absolute Pfade konvertieren und sie als solche zum PATH hinzufügen.
Um beispielsweise die Antwort von Guillaume Perrault-Archambault zu verbessern,
pathappend() {
for ARG in "$@"
do
if [ -d "$ARG" ] && [[ ":$PATH:" != *":$ARG:"* ]]; then
PATH="${PATH:+"$PATH:"}$ARG"
fi
done
}
wird
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. Grundlagen - Was nützt das?
Der readlink -f
Befehl konvertiert (unter anderem) einen relativen Pfad in einen absoluten Pfad. Dies ermöglicht es Ihnen, etwas zu tun
$ cd / path / to / my / bin / dir
$ pathappend .
$ echo "$ PATH"
<Ihr_alter_Pfad> : / path / to / my / bin / dir
2. Warum testen wir zweimal, ob wir im Pfad sind?
Betrachten Sie das obige Beispiel. Wenn der Benutzer
aus dem Verzeichnis ein zweites Mal sagt ,
wird . Natürlich wird in nicht vorhanden sein . Dann aber wird eingestellt
(die absoluten Pfad äquivalent ), das ist in bereits . Wir müssen also vermeiden , ein zweites Mal etwas hinzuzufügen .pathappend .
/path/to/my/bin/dir
ARG
.
.
PATH
ARGA
/path/to/my/bin/dir
.
PATH
/path/to/my/bin/dir
PATH
Vielleicht noch wichtiger ist, dass der Hauptzweck von readlink
, wie der Name schon sagt, darin besteht, einen symbolischen Link zu betrachten und den darin enthaltenen Pfadnamen auszulesen (dh auf diesen zu zeigen). Zum Beispiel:
$ 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
Nun, wenn Sie sagen pathappend /usr/lib/perl/5.14
, und Sie haben bereits /usr/lib/perl/5.14
in Ihrem Pfad, nun, das ist in Ordnung; wir können es einfach so lassen, wie es ist. Aber, wenn /usr/lib/perl/5.14
nicht bereits in Ihrer PATH ist, rufen wir readlink
und bekommen ARGA
= /usr/lib/perl/5.14.2
und dann fügen wir , dass zu PATH
. Aber warte eine Minute - wenn du es schon gesagt hast pathappend /usr/lib/perl/5.14
, dann hast du es bereits /usr/lib/perl/5.14.2
in deinem PFAD und wir müssen es erneut überprüfen, um zu vermeiden, dass es PATH
ein zweites Mal hinzugefügt wird.
3. Mit was ist das Geschäft if ARGA=$(readlink -f "$ARG")
?
Falls es unklar ist, prüft diese Zeile, ob das readlink
erfolgreich ist. Dies ist nur eine gute, defensive Programmierpraxis. Wenn wir die Ausgabe von Befehl m
als Teil von Befehl n verwenden (wobei m < n ist ), ist es ratsam, zu überprüfen, ob Befehl m fehlgeschlagen ist, und dies in irgendeiner Weise zu handhaben. Ich glaube nicht, dass dies wahrscheinlich readlink
scheitern wird - aber wie in Wie man den absoluten Pfad einer beliebigen Datei von OS X
und anderswo abruft , readlink
handelt es sich um eine GNU-Erfindung. Es ist in POSIX nicht spezifiziert, daher ist seine Verfügbarkeit unter Mac OS, Solaris und anderen Nicht-Linux-Unixen fraglich. (Tatsächlich habe ich gerade einen Kommentar gelesen , der besagt: „readlink -f
funktioniert anscheinend nicht unter Mac OS X 10.11.6, realpath
funktioniert aber sofort . “Wenn Sie sich also auf einem System befinden, das nicht über ein System verfügt readlink
oder auf dem readlink -f
es nicht funktioniert, können Sie dies möglicherweise ändern Skript zu verwenden realpath
.) Durch die Installation eines Sicherheitsnetzes machen wir unseren Code etwas portabler.
Wenn Sie sich auf einem System ohne readlink
(oder realpath
) befinden, werden Sie das natürlich nicht wollen .pathappend .
Der zweite -d
Test ( [ -d "$ARGA" ]
) ist wirklich wahrscheinlich unnötig. Ich kann mir kein Szenario vorstellen, in dem $ARG
ein Verzeichnis vorhanden und readlink
erfolgreich ist, das jedoch $ARGA
kein Verzeichnis ist. Ich habe nur die erste if
Anweisung kopiert und eingefügt , um die dritte Anweisung zu erstellen, und den -d
Test dort aus Faulheit verlassen.
4. Andere Kommentare?
Ja. Wie viele der anderen Antworten hier testet dieses Argument, ob es sich um ein Verzeichnis handelt, verarbeitet es, wenn dies der Fall ist, und ignoriert es, wenn dies nicht der Fall ist. Dies kann (oder auch nicht) angemessen sein, wenn Sie pathappend
nur .
Dateien (like .bash_profile
und .bashrc
) und andere Skripte verwenden. Aber wie diese Antwort (oben) gezeigt hat, ist es durchaus machbar, sie interaktiv zu nutzen. Sie werden sehr verwirrt sein, wenn Sie dies tun
$ pathappend /usr/local/nysql/bin
$ mysql
-bash: mysql: command not found
Ist Ihnen aufgefallen, dass ich nysql
im pathappend
Befehl statt gesagt habe mysql
? Und das pathappend
sagte nichts; es einfach stillschweigend das falsche argument ignoriert?
Wie ich oben sagte, ist es eine gute Praxis, mit Fehlern umzugehen. Hier ist ein Beispiel:
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
}