Odio seguir con otra implementación, pero necesitaba a) una implementación portátil y de shell puro , yb) cobertura de prueba unitaria , ya que el número de casos límite para algo como esto no es trivial .
Vea mi proyecto en Github para pruebas y código completo. Lo que sigue es una sinopsis de la implementación:
Como Keith Smith señala astutamente, readlink -f
hace dos cosas: 1) resuelve los enlaces simbólicos de forma recursiva y 2) canoniza el resultado, por lo tanto:
realpath() {
canonicalize_path "$(resolve_symlinks "$1")"
}
Primero, la implementación del solucionador de enlaces simbólicos:
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
}
Tenga en cuenta que esta es una versión ligeramente simplificada de la implementación completa . La implementación completa agrega una pequeña verificación para los ciclos de enlace simbólico , así como también masajea un poco la salida.
Finalmente, la función para canonizar una ruta:
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")
}
Eso es todo, más o menos. Suficientemente simple para pegar en su script, pero lo suficientemente complicado como para que se vuelva loco al confiar en cualquier código que no tenga pruebas unitarias para sus casos de uso.
readlink
puede ser un comando incorporado o un comando externo.