Ich hasse es, mit einer weiteren Umsetzung zu kommen, aber ich brauchte eine) eine portable, reine Shell-Implementierung und b) Abdeckung durch Unit-Tests da die Anzahl der Randfälle für so etwas nicht trivial .
Véase mein Projekt auf Github für Tests und vollständigen Code. Im Folgenden finden Sie eine Zusammenfassung der Implementierung:
Wie Keith Smith treffend bemerkt, readlink -f
tut zwei Dinge: 1) löst Symlinks rekursiv auf und 2) kanonisiert das Ergebnis, also:
realpath() {
canonicalize_path "$(resolve_symlinks "$1")"
}
Zunächst die Implementierung des Symlink-Auflösers:
resolve_symlinks() {
local dir_context path
path=$(readlink -- "$1")
if [ $? -eq 0 ]; then
dir_context=$(dirname -- "$1")
resolve_symlinks "$(_prepend_path_if_relative "$dir_context" "$path")"
else
printf '%s\n' "$1"
fi
}
_prepend_path_if_relative() {
case "$2" in
/* ) printf '%s\n' "$2" ;;
* ) printf '%s\n' "$1/$2" ;;
esac
}
Beachten Sie, dass dies eine leicht vereinfachte Version von die vollständige Umsetzung . Die vollständige Implementierung fügt eine kleine Prüfung auf Symlink-Zyklen hinzu und massiert die Ausgabe ein wenig.
Schließlich die Funktion zur Kanonisierung eines Pfades:
canonicalize_path() {
if [ -d "$1" ]; then
_canonicalize_dir_path "$1"
else
_canonicalize_file_path "$1"
fi
}
_canonicalize_dir_path() {
(cd "$1" 2>/dev/null && pwd -P)
}
_canonicalize_file_path() {
local dir file
dir=$(dirname -- "$1")
file=$(basename -- "$1")
(cd "$dir" 2>/dev/null && printf '%s/%s\n' "$(pwd -P)" "$file")
}
Das war's, mehr oder weniger. Einfach genug, um es in Ihr Skript einzufügen, aber knifflig genug, dass Sie verrückt wären, sich auf einen Code zu verlassen, der keine Unit-Tests für Ihre Anwendungsfälle hat.
1 Stimmen
Etwas spät, aber in Ihrer Frage fehlt ein Hinweis auf die von Ihnen verwendete Shell. Dies ist wichtig, denn
readlink
kann ein eingebauter oder ein externer Befehl sein.1 Stimmen
Das würde vielleicht den Unterschied erklären. Ich bin mir aber ziemlich sicher, dass ich bei beiden Gelegenheiten die Bash verwendet habe.
3 Stimmen
Warum ist diese Option auf Macs verboten?
0 Stimmen
@CommaToast - wenn ich mich recht erinnere, versuchen die Macs beim "Unix"-Teil des Betriebssystems, sich an POSIX- und/oder BSD-abgeleitete Tools und Dienstprogramme zu halten. Sie können GNU-Dienstprogramme auf OS/X installieren oder die Befehle so anpassen, dass sie eine "reine" Bourne-Shell verwenden (
/bin/sh
ohnebash
Erweiterungen). Für viele Entwickler sind heutzutage Shell-Skripte = Linux, GNU-Utilities undbash
so dass Probleme der Übertragbarkeit auftreten.5 Stimmen
Ich wünschte wirklich, Apple würde OS X dazu bringen, mehr Standard-Linux-Pfade zu unterstützen und sich um solche Dinge zu kümmern. Sie könnten es tun, ohne irgendetwas kaputt zu machen, oder?
1 Stimmen
@CommaToast Nun, sie werden mit Perl ausgeliefert, also ++ :-) ... öffnen Sie Terminal.app und geben Sie ein:
touch myfile ; ln -s myfile otherfile ; perl -MCwd=abs_path -le 'print abs_path readlink(shift);' otherfile
... in meinem Fall sehe ich: /Users/cito/myfile`. Ich habe es zu meiner Antwort unten hinzugefügt. Zum Wohl.1 Stimmen
@CommaToast GNU ist nicht Unix :-) Es wurde etwas hinzugefügt. Sie können eine Lösung mit
pwd -P
unter OS X, ohne etwas zu installieren1 Stimmen
@CommaToast
readlink
ist GPLv3 und Apple wird nichts anrühren, was unter der GPLv3 steht, da es erforderlich ist, einem Gerät kryptografische Schlüssel zu übergeben, um GPLv3-Software auf diesem Gerät zu ändern. gnu.org/licenses/ Das wird ein Grund dafür sein, dass die Standard-Shell nicht mehr Bash, sondern Zsh ist1 Stimmen
@JasonS aber FreeBSD hatte
readlink -f
seit irgendwann zwischen 2010 und 2012 abhängig vom Datum der Manpage und dem Datum der BSD-Veröffentlichung, und das ist keine GPL-Implementierung. Apple zögert also nur. Und tatsächlich,readlink -f
hat seinen Ursprung in OpenBSD 2.1 im Jahr 1997, soweit ich das beurteilen kann. Die erste Implementierung war also nicht einmal GNU. Ich kann verstehen, dass es nicht in Snow Leopard ist, aber ich kann nicht verstehen, dass es nicht in Mavericks/Sierra ist.0 Stimmen
@WyattWard Gutes Argument. Der einzige Mac, zu dem ich Zugang habe (10.11 Big Sur), hat das Datum des Readlinks von 2003. Also ja, es könnte aktualisiert werden. Und wie du sagst, nicht GPLv3 überhaupt, so ignorieren Sie meine früheren Kommentar über es GPLv3. Ich war ein bisschen blind, weil sich so viele Leute darüber beschwert haben, dass Mac OS nicht GNU ist. Nein, ist es nicht. Wird es auch nie sein. Aber der Punkt bleibt, dass man die Arbeit trotzdem erledigen kann mit
pwd -P
ohne zu wünschen, dass Mac OS ein GNU Linux ist, indem man Homebrew benutzt. Ja, Shell-Skripte sind nicht portabel. Das gilt nicht nur für Mac OS.4 Stimmen
MacOS 12.3 unterstützt
readlink -f
.