Saya benci untuk melanjutkan dengan implementasi lain, tetapi saya membutuhkan a) implementasi portabel, shell murni , dan b) cakupan unit-test , karena jumlah kasus tepi untuk sesuatu seperti ini adalah non-sepele .
Lihat proyek saya di Github untuk tes dan kode lengkap. Berikut ini adalah sinopsis implementasi:
Seperti yang ditunjukkan Keith Smith dengan cerdas, readlink -f
lakukan dua hal: 1) menyelesaikan symlink secara rekursif, dan 2) mengkanoniskan hasilnya, dengan demikian:
realpath() {
canonicalize_path "$(resolve_symlinks "$1")"
}
Pertama, implementasi resollink symlink:
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
}
Perhatikan bahwa ini adalah versi implementasi penuh yang sedikit disederhanakan . Implementasi penuh menambahkan cek kecil untuk siklus symlink , serta memijat output sedikit.
Akhirnya, fungsi untuk mengkanonik jalur:
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")
}
Itu dia, kurang lebih. Cukup sederhana untuk disisipkan ke skrip Anda, tetapi cukup rumit sehingga Anda akan gila untuk mengandalkan kode apa pun yang tidak memiliki tes unit untuk kasus penggunaan Anda.
readlink
dapat berupa builtin atau perintah eksternal.