You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
1.7 KiB
Bash
81 lines
1.7 KiB
Bash
4 years ago
|
#!/bin/sh
|
||
|
|
||
|
set -eu
|
||
|
|
||
|
realpath_canonical() {
|
||
|
# resolve symlink (if there is one) and use $@ to detect symlink loops
|
||
|
while [ -L "$1" ] && target=$(readlink -- "$1"); do
|
||
|
REPLY=$(dirname "$1")
|
||
|
# Resolve relative to symlink's directory
|
||
|
if [ "$REPLY" = "." ]; then
|
||
|
REPLY=$target
|
||
|
else
|
||
|
case "$target" in
|
||
|
/*)
|
||
|
REPLY=$target;;
|
||
|
*)
|
||
|
REPLY=$REPLY/$target;;
|
||
|
esac
|
||
|
fi
|
||
|
# Break out if we found a symlink loop
|
||
|
for target in "$@"; do [ "$REPLY" = "$target" ] && break 2; done
|
||
|
# Add to the loop-detect list and tail-recurse
|
||
|
set -- "$REPLY" "$@"
|
||
|
done
|
||
|
# recurse unless root
|
||
|
REPLY=$(dirname "$1")
|
||
|
if [ "$REPLY" != "/" ] && [ "$REPLY" != "." ]; then
|
||
|
REPLY=$(realpath_canonical "$REPLY");
|
||
|
fi
|
||
|
# set $1 to dirname and $2 to basename
|
||
|
set -- "$REPLY" "$(basename "$1")"
|
||
|
# combine canon parent w/basename
|
||
|
REPLY=$PWD
|
||
|
while [ $# -gt 0 ]; do
|
||
|
# handle case of component starting with double slash and no
|
||
|
# other slashes separately because it cannot be solved by
|
||
|
# globbing
|
||
|
if echo "$1" | grep -E '^//[^/]*$' >/dev/null 2>&1; then
|
||
|
REPLY=//
|
||
|
first=$(echo "$1" | cut -c3-)
|
||
|
shift
|
||
|
set -- "$first" "$@"
|
||
|
continue
|
||
|
fi
|
||
|
# all other cases can be expressed by globbing
|
||
|
case $1 in
|
||
|
/*)
|
||
|
REPLY=/
|
||
|
first=$(echo "$1" | sed -e 's/^\/\+//')
|
||
|
shift
|
||
|
set -- "$first" "$@"
|
||
|
;;
|
||
|
*/*)
|
||
|
front=${1%%/*}
|
||
|
back=$(echo "$1" | sed -e "s/^$front\\/\\+//")
|
||
|
shift
|
||
|
set -- "$front" "$back" "$@"
|
||
|
;;
|
||
|
''|.)
|
||
|
shift
|
||
|
;;
|
||
|
..)
|
||
|
REPLY=$(dirname "$REPLY")
|
||
|
shift
|
||
|
;;
|
||
|
*)
|
||
|
REPLY="${REPLY%/}/$1"
|
||
|
shift
|
||
|
;;
|
||
|
esac
|
||
|
done
|
||
|
echo "$REPLY"
|
||
|
}
|
||
|
|
||
|
if [ $# -ne 1 ]; then
|
||
|
echo "usage: $0 path"
|
||
|
exit 1
|
||
|
fi
|
||
|
|
||
|
realpath_canonical "$1"
|