Ich hasse es, mich mit einer weiteren Implementierung zu beschäftigen, aber ich brauchte a) eine tragbare, reine Shell-Implementierung und b) eine Unit-Test-Abdeckung , da die Anzahl der Randfälle für so etwas nicht trivial ist .
Siehe mein Projekt auf Github Tests und vollständigen Code. Was folgt, ist eine Zusammenfassung der Implementierung:
Keith Smith weist scharfsinnig darauf hin, readlink -f
dass er zwei Dinge tut: 1) Symlinks rekursiv auflöst und 2) das Ergebnis kanonisiert, daher:
realpath() {
canonicalize_path "$(resolve_symlinks "$1")"
}
Zunächst die Implementierung des Symlink-Resolvers:
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 der vollständigen Implementierung ist . Die vollständige Implementierung fügt eine kleine Überprüfung für Symlink-Zyklen hinzu und massiert die Ausgabe ein wenig.
Schließlich die Funktion zum Kanonisieren 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 in Ihr Skript eingefügt zu werden, aber schwierig genug, dass Sie verrückt wären, sich auf Code zu verlassen, der keine Komponententests für Ihre Anwendungsfälle enthält.
readlink
sich um einen integrierten oder einen externen Befehl handeln kann.