add realpath_m.sh as an all-in-one replacement for realpath -m
This commit is contained in:
parent
b9c659a70a
commit
dda942d7f1
4 changed files with 108 additions and 18 deletions
|
@ -35,4 +35,4 @@ To verify that the script works with busybox:
|
|||
|
||||
$ mkdir busybox
|
||||
$ busybox --install -s busybox
|
||||
$ PATH=$(pwd)/busybox ./test.sh
|
||||
$ PATH=$(pwd)/busybox /bin/busybox sh ./test.sh
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env sh
|
||||
#!/bin/sh
|
||||
|
||||
# Sets REPLY to the absolute, well-formed path of a physical directory that
|
||||
# contains (or would contain) the supplied path. (Equivalent to the dirname of
|
||||
|
|
80
realpath_m.sh
Executable file
80
realpath_m.sh
Executable file
|
@ -0,0 +1,80 @@
|
|||
#!/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"
|
42
test.sh
42
test.sh
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
set -eu
|
||||
|
||||
# we use the full path to realpath so that the coreutils version of realpath is
|
||||
# used even when run with busybox in $PATH
|
||||
|
@ -8,6 +8,10 @@ realpath_m() {
|
|||
REPLY=$(/usr/bin/realpath -m "$1")
|
||||
}
|
||||
|
||||
realpath_m2() {
|
||||
REPLY=$("$origpwd/realpath_m.sh" "$1")
|
||||
}
|
||||
|
||||
assert() {
|
||||
expected=$1
|
||||
shift
|
||||
|
@ -25,6 +29,7 @@ compare() {
|
|||
assert "$("$cmd" "$@")" realpath_"$cmd" "$@"
|
||||
}
|
||||
|
||||
origpwd=$(pwd)
|
||||
numokay=0
|
||||
numfail=0
|
||||
|
||||
|
@ -131,14 +136,14 @@ rm x y z; rmdir q
|
|||
|
||||
# Current directory:
|
||||
|
||||
for cmd in realpath_canonical realpath_m; do
|
||||
for cmd in realpath_canonical realpath_m realpath_m2; do
|
||||
assert "$PWD" "$cmd" .
|
||||
assert "$PWD" "$cmd" "$PWD"
|
||||
done
|
||||
|
||||
# Nonexistent file:
|
||||
|
||||
for cmd in realpath_canonical realpath_m; do
|
||||
for cmd in realpath_canonical realpath_m realpath_m2; do
|
||||
assert "$PWD/x" "$cmd" x
|
||||
assert "$PWD/x" "$cmd" "$PWD/x"
|
||||
done
|
||||
|
@ -146,7 +151,7 @@ done
|
|||
# Symlink to non-existent target:
|
||||
|
||||
ln -s y x
|
||||
for cmd in realpath_canonical realpath_m; do
|
||||
for cmd in realpath_canonical realpath_m realpath_m2; do
|
||||
assert "$PWD/y" "$cmd" x
|
||||
assert "$PWD/y" "$cmd" "$PWD/x"
|
||||
done
|
||||
|
@ -155,7 +160,7 @@ done
|
|||
# Symlink chain:
|
||||
|
||||
ln -s z y
|
||||
for cmd in realpath_canonical realpath_m; do
|
||||
for cmd in realpath_canonical realpath_m realpath_m2; do
|
||||
assert "$PWD/z" "$cmd" x
|
||||
assert "$PWD/z" "$cmd" "$PWD/x"
|
||||
done
|
||||
|
@ -167,6 +172,7 @@ ln -s y z
|
|||
# difference to realpath -m: returned path is the target
|
||||
assert "$PWD/z" realpath_canonical x
|
||||
assert "$PWD/y" realpath_m x
|
||||
assert "$PWD/z" realpath_m2 x
|
||||
rm x y z
|
||||
|
||||
|
||||
|
@ -177,19 +183,19 @@ mkdir z
|
|||
ln -s $PWD/y x
|
||||
ln -s $PWD/x z/x
|
||||
|
||||
for cmd in realpath_canonical realpath_m; do
|
||||
for cmd in realpath_canonical realpath_m realpath_m2; do
|
||||
assert "$PWD/y" "$cmd" x
|
||||
assert "$PWD/y" "$cmd" z/x
|
||||
done
|
||||
|
||||
ln -sf ../x z/x
|
||||
for cmd in realpath_canonical realpath_m; do
|
||||
for cmd in realpath_canonical realpath_m realpath_m2; do
|
||||
assert "$PWD/y" "$cmd" x
|
||||
assert "$PWD/y" "$cmd" z/x
|
||||
done
|
||||
|
||||
ln -s z q
|
||||
for cmd in realpath_canonical realpath_m; do
|
||||
for cmd in realpath_canonical realpath_m realpath_m2; do
|
||||
assert "$PWD/z" "$cmd" q
|
||||
assert "$PWD/y" "$cmd" q/../x
|
||||
assert "$PWD/z/a" "$cmd" q/a
|
||||
|
@ -211,7 +217,7 @@ assert "$PWD/q/foo" realpath_location q/foo/bar
|
|||
|
||||
### Missing elements
|
||||
|
||||
for cmd in realpath_canonical realpath_m; do
|
||||
for cmd in realpath_canonical realpath_m realpath_m2; do
|
||||
assert "$PWD/z/foo/bar/baz" "$cmd" q/foo/bar/baz
|
||||
assert "$PWD/z/foo/bar" "$cmd" q/foo/bar
|
||||
assert /non-existent "$cmd" /non-existent
|
||||
|
@ -224,7 +230,7 @@ done
|
|||
|
||||
mkdir foo
|
||||
cd foo
|
||||
for cmd in realpath_canonical realpath_m; do
|
||||
for cmd in realpath_canonical realpath_m realpath_m2; do
|
||||
assert "$OLDPWD/z" "$cmd" "$OLDPWD/q"
|
||||
assert "$OLDPWD/y" "$cmd" "$OLDPWD/q/x"
|
||||
assert "$OLDPWD/y" "$cmd" "../q/x"
|
||||
|
@ -234,15 +240,19 @@ done
|
|||
# We can follow symlinks even if $PWD is inaccessible:
|
||||
|
||||
rmdir ../foo
|
||||
assert "$OLDPWD/z" realpath_canonical "$OLDPWD/q"
|
||||
assert "$OLDPWD/y" realpath_canonical "../q/x"
|
||||
for cmd in realpath_canonical; do
|
||||
assert "$OLDPWD/z" "$cmd" "$OLDPWD/q"
|
||||
assert "$OLDPWD/y" "$cmd" "../q/x"
|
||||
done
|
||||
|
||||
# And we can do non-symlink canonicalizing on the base dir of the results:
|
||||
|
||||
assert "$OLDPWD/z" realpath_canonical "../z"
|
||||
assert "$OLDPWD/z/foo" realpath_canonical "../z/foo"
|
||||
assert "$OLDPWD/foo" realpath_canonical "../foo"
|
||||
assert "$OLDPWD/z" realpath_canonical "../q"
|
||||
for cmd in realpath_canonical; do
|
||||
assert "$OLDPWD/z" "$cmd" "../z"
|
||||
assert "$OLDPWD/z/foo" "$cmd" "../z/foo"
|
||||
assert "$OLDPWD/foo" "$cmd" "../foo"
|
||||
assert "$OLDPWD/z" "$cmd" "../q"
|
||||
done
|
||||
|
||||
cd ..
|
||||
|
||||
|
|
Loading…
Reference in a new issue