Ich bin ein bisschen überrascht, dass dies noch niemand erwähnt hat, aber Sie können readlink -frelative 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 -fBefehl 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/dirARG..PATHARGA/path/to/my/bin/dir.PATH/path/to/my/bin/dirPATH
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.14in Ihrem Pfad, nun, das ist in Ordnung; wir können es einfach so lassen, wie es ist. Aber, wenn /usr/lib/perl/5.14nicht bereits in Ihrer PATH ist, rufen wir readlinkund bekommen ARGA= /usr/lib/perl/5.14.2und 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.2in deinem PFAD und wir müssen es erneut überprüfen, um zu vermeiden, dass es PATHein 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 readlinkerfolgreich 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 readlinkscheitern wird - aber wie in Wie man den absoluten Pfad einer beliebigen Datei von OS X
und anderswo abruft , readlinkhandelt 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 -ffunktioniert anscheinend nicht unter Mac OS X 10.11.6, realpathfunktioniert aber sofort . “Wenn Sie sich also auf einem System befinden, das nicht über ein System verfügt readlinkoder auf dem readlink -fes 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 -dTest ( [ -d "$ARGA" ]) ist wirklich wahrscheinlich unnötig. Ich kann mir kein Szenario vorstellen, in dem $ARGein Verzeichnis vorhanden und readlinkerfolgreich ist, das jedoch $ARGAkein Verzeichnis ist. Ich habe nur die erste ifAnweisung kopiert und eingefügt , um die dritte Anweisung zu erstellen, und den -dTest 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_profileund .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 pathappendBefehl statt gesagt habe mysql? Und das pathappendsagte 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
}