Ich versuche, den absoluten Pfad zum aktuell ausgeführten Skript unter OS X zu ermitteln.
Ich habe viele Antworten gesehen readlink -f $0
. Da OS X readlink
mit BSD identisch ist, funktioniert es einfach nicht (es funktioniert mit der GNU-Version).
Gibt es dafür eine sofort einsatzbereite Lösung?
$( cd "$(dirname "$0")" ; pwd -P )
Antworten:
Es gibt eine
realpath()
C-Funktion, die den Job erledigt, aber ich sehe nichts in der Befehlszeile. Hier ist ein schneller und schmutziger Ersatz:Dies gibt den Pfad wörtlich aus, wenn er mit a beginnt
/
. Wenn nicht, muss es ein relativer Pfad sein, also geht es$PWD
nach vorne. Das#./
Teil wird./
von vorne abgezogen$1
.quelle
realpath ../something
Rückkehr$PWD/../something
command -v realpath >/dev/null 2>&1 || realpath() { ... }
Diese drei einfachen Schritte werden dieses und viele andere OS X-Probleme lösen:
brew install coreutils
grealpath .
(3) kann auf nur geändert werden
realpath
, siehe (2) Ausgabequelle
$( cd "$(dirname "$0")" ; pwd -P )
die für mich gut funktionieren.XXX
und einescd xxx
dannpwd
zurückkehrt.../xxx
. Mit Ausnahme dieser Antwort kehren alle oben genannten Lösungen zurück,xxx
wenn Sie wirklich wollenXXX
. Danke dir!realpath
, was passiert dann, wenn Sie mit ziemlicher Sicherheit andere Artikel von benötigencoreutils
? Diese Funktionen auch in Bash umschreiben? : PPfui. Ich fand die vorherigen Antworten aus einigen Gründen etwas mangelhaft: Insbesondere lösen sie nicht mehrere Ebenen symbolischer Links auf und sind extrem "Bash-y". Während in der ursprünglichen Frage ausdrücklich nach einem "Bash-Skript" gefragt wird, wird auch die BSD-ähnliche Nicht-GNU von Mac OS X erwähnt
readlink
. Hier ist also ein Versuch einer vernünftigen Portabilität (ich habe ihn mit bash als 'sh' und einem Strich überprüft), bei dem eine beliebige Anzahl symbolischer Links aufgelöst wird. und es sollte auch mit Leerzeichen in den Pfaden funktionieren, obwohl ich mir nicht sicher bin, ob der Basisname des Dienstprogramms selbst Leerzeichen enthält. Vermeiden Sie das also, ähm?Hoffe, das kann jemandem von Nutzen sein.
quelle
local
Variablen zu verwenden , die innerhalb der Funktion definiert sind, um den globalen Namespace nicht zu verschmutzen. ZBlocal OURPWD=...
. Funktioniert zumindest für Bash.BASENAME=$(basename "$LINK")
Basisnamen haben, ist es wahrscheinlich eine gute Idee, innerhalb der Weile einen hinzuzufügen und diesen im zweiten LINK-Setter und im REALPATH-Setter zu verwenden..
übergeordnete Refs nicht so, wie es der Fallrealpath
wäre.coreutils
Versuchen Sie esln -s /var/log /tmp/linkexample
dann mit installiertem Homebrewrealpath /tmp/linkexample/../
. Dies wird gedruckt/private/var
. Aber Ihre Funktion erzeugt/tmp/linkexample/..
stattdessen, weil..
es sich nicht um einen Symlink handelt.Eine befehlszeilenfreundlichere Variante der Python-Lösung:
quelle
python -c "import os; import sys; print(os.path.realpath(sys.argv[1]))"
Ich suchte nach einer Lösung für die Verwendung in einem Systembereitstellungsskript, dh vor der Installation von Homebrew. Ohne eine geeignete Lösung würde ich die Aufgabe einfach in eine plattformübergreifende Sprache verlagern, z. B. Perl:
Was wir eigentlich wollen, ist das enthaltende Verzeichnis:
quelle
FULLPATH=$(perl -e "use Cwd 'abs_path'; print abs_path('$0')")
. Irgendein Grund dagegen?''
ist nicht kugelsicher. Es bricht ab, wenn es beispielsweise$0
ein einfaches Anführungszeichen enthält. Ein sehr einfaches Beispiel: Probieren Sie Ihre Version aus/tmp/'/test.sh
und rufen Sie/tmp/'/test.sh
den vollständigen Pfad auf./tmp/'.sh
.Da gibt es einen realen Weg, wie andere betont haben:
Makefile:
Dann kompilieren Sie mit
make
und fügen Sie einen Softlink ein mit:ln -s $(pwd)/realpath /usr/local/bin/realpath
quelle
gcc realpath.c -o /usr/local/bin/realpath
?/usr/local/bin
Verwenden Sie Python, um es zu bekommen:
quelle
Unter macOS ist die einzige Lösung, die ich gefunden habe, um Symlinks zuverlässig zu verarbeiten, die Verwendung von
realpath
. Da dies erforderlich istbrew install coreutils
, habe ich diesen Schritt nur automatisiert. Meine Implementierung sieht folgendermaßen aus:Diese Fehler, wenn sie nicht
brew
installiert haben, aber Sie können das alternativ auch einfach installieren. Ich fühlte mich einfach nicht wohl dabei, etwas zu automatisieren, das beliebigen Ruby-Code aus dem Netz kräuselt.Beachten Sie, dass dies eine automatisierte Variation der Antwort von Oleg Mikheev ist .
Ein wichtiger Test
Ein guter Test für eine dieser Lösungen ist:
ln -s
) zu dieser DateiDereferenziert die Lösung den Symlink und gibt Ihnen das ursprüngliche Verzeichnis? Wenn ja, funktioniert es.
quelle
dirname
gibt den Verzeichnisnamen von/path/to/file
, dh/path/to
.cd /path/to; pwd
stellt sicher, dass der Pfad absolut ist.basename
gibt nur den Dateinamen ein/path/to/file
, dhfile
.quelle
Wie Sie oben sehen können, habe ich vor ungefähr 6 Monaten einen Versuch unternommen. Ich habe es total vergessen, bis ich wieder etwas Ähnliches brauchte. Ich war völlig geschockt zu sehen, wie rudimentär es war; Ich lehre mich seit ungefähr einem Jahr ziemlich intensiv das Codieren, aber ich habe oft das Gefühl, dass ich vielleicht gar nichts gelernt habe, wenn die Dinge am schlimmsten sind.
Ich würde die oben genannte "Lösung" entfernen, aber ich mag es wirklich, wenn ich aufzeichne, wie viel ich in den letzten Monaten wirklich gelernt habe.
Aber ich schweife ab. Ich habe mich letzte Nacht hingesetzt und alles ausgearbeitet. Die Erklärung in den Kommentaren sollte ausreichend sein. Wenn Sie die Kopie verfolgen möchten, an der ich weiter arbeite, können Sie diesem Kern folgen. Dies macht wahrscheinlich das, was Sie brauchen.
quelle
..
übergeordneten Referenzen auflöst . zB/foo/link_to_other_directory/..
wird/foo
eher als das übergeordnete Element des Pfads aufgelöst, auf den der Symlink/foo/link_to_other_directory
zeigt.readlink -f
und jede Pfadkomponenterealpath
auflösen, beginnend am Stammverzeichnis und Aktualisierung der vorangestellten Verbindungsziele auf den Rest, der noch verarbeitet wird. Ich habe dieser Frage eine Antwort hinzugefügt, die diese Logik neu implementiert.Realpath für Mac OS X.
Beispiel mit verwandtem Pfad:
Beispiel mit Home-Ordner
quelle
..
ergibt sich nicht die richtige antwort, also habe ich eine überprüfung hinzugefügt, ob der angegebene pfad ein verzeichnis ist:if test -d $path ; then echo $(cd "$path"; pwd) ; else [...]
"$(dirname $(dirname $(realpath $0)))"
funktioniert, also brauche ich etwas anderes ...echo
sollte auch nicht begangen werden...
Verweise werden vor dem Auflösen von Symlinks aufgelöst, nicht danach. Versuchen Sie dies mitcoreutils
installiertem Homebrew , erstellen Sie einen Link mitln -s /var/log /tmp/linkexample
und führen Sie ihn ausrealpath /tmp/linkexample/../
. Dies wird gedruckt/private/var
. Aber Ihre Funktion produziert/tmp/linkexample/..
stattdessen, weilpwd
immer noch/tmp/linkexample
nach der CD angezeigt wird.Dies scheint für OSX zu funktionieren, erfordert keine Binärdateien und wurde von hier gezogen
quelle
Ich mag das:
quelle
Ich brauchte einen
realpath
Ersatz auf OS X, eine , die richtig auf Wegen mit Symlinks und Eltern Referenzen arbeitet wiereadlink -f
Would . Dies umfasst das Auflösen von Symlinks im Pfad vor dem Auflösen übergeordneter Referenzen. Wenn Sie beispielsweise die Homebrew-coreutils
Flasche installiert haben, führen Sie Folgendes aus:Beachten Sie, dass dies vor dem Auflösen der übergeordneten Verzeichnisreferenz
readlink -f
behoben wurde . Natürlich gibt es keine auf Mac entweder ./tmp/linkeddir
..
readlink -f
Als Teil der a bash-Implementierung für habe
realpath
ich in Bash 3.2 erneut implementiert, was ein GNUlib-canonicalize_filename_mode(path, CAN_ALL_BUT_LAST)
Funktionsaufruf bewirkt . Dies ist auch der Funktionsaufruf, den GNUreadlink -f
ausführt:Es umfasst die Erkennung kreisförmiger Symlinks, die beendet wird, wenn derselbe (Zwischen-) Pfad zweimal gesehen wird.
Wenn Sie nur Folgendes benötigen
readlink -f
, können Sie Folgendes verwenden:Denn
realpath
ich brauchte--relative-to
und--relative-base
unterstütze auch, die dir nach der Kanonisierung relative Wege geben:Ich habe Unit-Tests in meine Code Review-Anfrage für diesen Code aufgenommen .
quelle
Aufgrund der Kommunikation mit dem Kommentator stimmte ich zu, dass es sehr schwierig ist und keine andere Möglichkeit hat, einen Realpath zu implementieren, der sich genauso verhält wie Ubuntu.
Aber die folgende Version kann Eckfälle behandeln, die beste Antwort kann nicht und meine täglichen Bedürfnisse auf MacBook befriedigen. Fügen Sie diesen Code in Ihr ~ / .bashrc ein und denken Sie daran:
quelle
echo
vermeiden . Genausopwd
wieecho $(pwd)
ohne eine zweite Kopie der Shell erzeugen zu müssen. Außerdemecho
ist es ein Fehler , das Argument nicht zu zitieren (Sie verlieren führende oder nachfolgende Leerzeichen, benachbarte interne Leerzeichen und erweiterte Platzhalter usw.). Siehe weitere stackoverflow.com/questions/10067266/…realpath
eines nicht vorhandenen Verzeichnisses anfordern .dir=$(dirname "$1"); file=$(basename "$1")
Gründen der Konsistenz bevorzugen Sie wahrscheinlich anstelle der lang veralteten Backtick-Syntax. Beachten Sie auch wieder das korrekte Zitieren von Argumenten.