Pfad des aktuellen Skripts abrufen, wenn es über einen Symlink ausgeführt wird

58

Ich habe ein Hilfsprogramm, das aus einigen Verzeichnissen mit einigen Bash-Skripten und unterstützenden Dateien besteht, die möglicherweise in einem anderen Verzeichnis auf jedem Computer auf mehreren Computern bereitgestellt werden. Die Skripte müssen in der Lage sein, Pfade relativ zu sich selbst zu referenzieren, damit ich den Pfad zu der Datei erhalten kann, die gerade ausgeführt wird.

Mir ist die dirname $0Redewendung bekannt, die perfekt funktioniert, wenn mein Skript direkt aufgerufen wird. Leider besteht der Wunsch, in der Lage zu sein, Symlinks zu diesen Skripten aus einem völlig anderen Verzeichnis zu erstellen und dennoch die relative Pfadlogik zu verwenden.

Ein Beispiel für die gesamte Trocknungsstruktur ist wie folgt:

/
 |-usr/local/lib
 |  |-foo
 |  |  |-bin
 |  |  |  |-script.sh
 |  |  |-res
 |  |  |  |-resource_file.txt
 |-home/mike/bin
 |  |-link_to_script (symlink to /usr/local/lib/foo/bin/script.sh)

Wie kann ich sicher Referenz /usr/local/lib/foo/res/resource_file.txtaus , script.shob sie von aufgerufen wird , /usr/local/lib/foo/bin/script.shoder ~mike/bin/link_to_script?

Mike Deck
quelle

Antworten:

79

Versuchen Sie dies als allgemeine Lösung:

DIR="$(cd "$(dirname "$0")" && pwd)"

Im konkreten Fall folgender Symlinks können Sie dies auch tun:

DIR="$(dirname "$(readlink -f "$0")")"
Caleb
quelle
Funktioniert perfekt und ist viel einfacher als das, was ich versucht habe. Vielen Dank!
Mike Deck
@ MikeDeck Viel Spaß. Beachten Sie, dass ich seit dem ersten Posting einige Probleme mit Zitaten behoben habe ... Sie könnten eine Option aus der letzten Bearbeitung verwenden, falls Sie irgendwann Leerzeichen oder andere verrückte Zeichen in Ihrem Pfad haben. Auch wenn es für dieses Projekt keine Rolle spielt, können Sie den Code von Ihren eigenen Skripten kopieren, und dann ist es wichtig, die beste Option zu haben!
Caleb
1
Ich sollte klarstellen, das zweite funktioniert einwandfrei. Die erste Lösung, die Sie angegeben haben, funktioniert nicht für Symlinks auf meinem System.
Mike Deck
4
@MikeDeck: Die erste Lösung funktioniert für den typischen Fall, dass verschiedene Verzeichnisse als Teil des Pfads verknüpft sind, hilft aber nicht, wenn die endgültige Binärdatei ein Symlink ist. Darum kümmert sich der Zweite.
Caleb
1
Funktioniert nicht, wenn die Skriptdatei sourced ist (zB $ source ./sript.sh) Dies funktioniert in beiden Fällen:DIR="$(cd "$(dirname "$BASH_SOURCE")" && pwd)"
FractalSpace
7

eine Linie:

cd $(dirname $([ -L $0 ] && readlink -f $0 || echo $0))
Diyismus
quelle
2
Einzeilige Antworten sind in der Regel nicht besonders hilfreich. Bitte erwägen Sie, Ihre Antwort durch Erläuterungen, Links oder Dokumentationen zu erweitern, die Ihren Lösungsvorschlag weiter unterstützen.
HalosGhost
1
Eigentlich brauchen Sie das nicht zu tun, Readlink-Version der ursprünglichen Antwort funktioniert einwandfrei, wenn überhaupt kein Symlink beteiligt ist
THESorcerer
3

readlink -f funktioniert bei mir nicht, ich habe diesen Fehler:

readlink: illegal option -- f
usage: readlink [-n] [file ...]

Aber das funktioniert gut:

DIR="$(dirname "$(readlink "$0")")"
echo $DIR
Kevin Campion
quelle
3
Dann bist du auf einem Mac und dies sollte deine Frage beantworten .
Isaac
Ja, ich bin auf MacOs @isaac, aber ich habe keine Frage. Ich habe den Befehl gepostet, der auf meiner Seite funktioniert.
Kevin Campion
0

Eine kleine Ergänzung zum obigen Skript. Die Option -P für pwd folgt symlinks

DIR="$(cd "$(dirname "$0")" && pwd -P)"
user2108420
quelle
7
Dies funktioniert nur, wenn der Symlink Teil der Verzeichnisstruktur ist. Es funktioniert nicht, wenn die Datei selbst verknüpft ist.
Oliver Gondža