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
|
$ mkdir busybox
|
||||||
$ busybox --install -s 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
|
# 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
|
# 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
|
#!/bin/sh
|
||||||
|
|
||||||
set -e
|
set -eu
|
||||||
|
|
||||||
# we use the full path to realpath so that the coreutils version of realpath is
|
# we use the full path to realpath so that the coreutils version of realpath is
|
||||||
# used even when run with busybox in $PATH
|
# used even when run with busybox in $PATH
|
||||||
|
@ -8,6 +8,10 @@ realpath_m() {
|
||||||
REPLY=$(/usr/bin/realpath -m "$1")
|
REPLY=$(/usr/bin/realpath -m "$1")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
realpath_m2() {
|
||||||
|
REPLY=$("$origpwd/realpath_m.sh" "$1")
|
||||||
|
}
|
||||||
|
|
||||||
assert() {
|
assert() {
|
||||||
expected=$1
|
expected=$1
|
||||||
shift
|
shift
|
||||||
|
@ -25,6 +29,7 @@ compare() {
|
||||||
assert "$("$cmd" "$@")" realpath_"$cmd" "$@"
|
assert "$("$cmd" "$@")" realpath_"$cmd" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
origpwd=$(pwd)
|
||||||
numokay=0
|
numokay=0
|
||||||
numfail=0
|
numfail=0
|
||||||
|
|
||||||
|
@ -131,14 +136,14 @@ rm x y z; rmdir q
|
||||||
|
|
||||||
# Current directory:
|
# 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" .
|
||||||
assert "$PWD" "$cmd" "$PWD"
|
assert "$PWD" "$cmd" "$PWD"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Nonexistent file:
|
# 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" x
|
||||||
assert "$PWD/x" "$cmd" "$PWD/x"
|
assert "$PWD/x" "$cmd" "$PWD/x"
|
||||||
done
|
done
|
||||||
|
@ -146,7 +151,7 @@ done
|
||||||
# Symlink to non-existent target:
|
# Symlink to non-existent target:
|
||||||
|
|
||||||
ln -s y x
|
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" x
|
||||||
assert "$PWD/y" "$cmd" "$PWD/x"
|
assert "$PWD/y" "$cmd" "$PWD/x"
|
||||||
done
|
done
|
||||||
|
@ -155,7 +160,7 @@ done
|
||||||
# Symlink chain:
|
# Symlink chain:
|
||||||
|
|
||||||
ln -s z y
|
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" x
|
||||||
assert "$PWD/z" "$cmd" "$PWD/x"
|
assert "$PWD/z" "$cmd" "$PWD/x"
|
||||||
done
|
done
|
||||||
|
@ -167,6 +172,7 @@ ln -s y z
|
||||||
# difference to realpath -m: returned path is the target
|
# difference to realpath -m: returned path is the target
|
||||||
assert "$PWD/z" realpath_canonical x
|
assert "$PWD/z" realpath_canonical x
|
||||||
assert "$PWD/y" realpath_m x
|
assert "$PWD/y" realpath_m x
|
||||||
|
assert "$PWD/z" realpath_m2 x
|
||||||
rm x y z
|
rm x y z
|
||||||
|
|
||||||
|
|
||||||
|
@ -177,19 +183,19 @@ mkdir z
|
||||||
ln -s $PWD/y x
|
ln -s $PWD/y x
|
||||||
ln -s $PWD/x z/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" x
|
||||||
assert "$PWD/y" "$cmd" z/x
|
assert "$PWD/y" "$cmd" z/x
|
||||||
done
|
done
|
||||||
|
|
||||||
ln -sf ../x z/x
|
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" x
|
||||||
assert "$PWD/y" "$cmd" z/x
|
assert "$PWD/y" "$cmd" z/x
|
||||||
done
|
done
|
||||||
|
|
||||||
ln -s z q
|
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/z" "$cmd" q
|
||||||
assert "$PWD/y" "$cmd" q/../x
|
assert "$PWD/y" "$cmd" q/../x
|
||||||
assert "$PWD/z/a" "$cmd" q/a
|
assert "$PWD/z/a" "$cmd" q/a
|
||||||
|
@ -211,7 +217,7 @@ assert "$PWD/q/foo" realpath_location q/foo/bar
|
||||||
|
|
||||||
### Missing elements
|
### 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/baz" "$cmd" q/foo/bar/baz
|
||||||
assert "$PWD/z/foo/bar" "$cmd" q/foo/bar
|
assert "$PWD/z/foo/bar" "$cmd" q/foo/bar
|
||||||
assert /non-existent "$cmd" /non-existent
|
assert /non-existent "$cmd" /non-existent
|
||||||
|
@ -224,7 +230,7 @@ done
|
||||||
|
|
||||||
mkdir foo
|
mkdir foo
|
||||||
cd 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/z" "$cmd" "$OLDPWD/q"
|
||||||
assert "$OLDPWD/y" "$cmd" "$OLDPWD/q/x"
|
assert "$OLDPWD/y" "$cmd" "$OLDPWD/q/x"
|
||||||
assert "$OLDPWD/y" "$cmd" "../q/x"
|
assert "$OLDPWD/y" "$cmd" "../q/x"
|
||||||
|
@ -234,15 +240,19 @@ done
|
||||||
# We can follow symlinks even if $PWD is inaccessible:
|
# We can follow symlinks even if $PWD is inaccessible:
|
||||||
|
|
||||||
rmdir ../foo
|
rmdir ../foo
|
||||||
assert "$OLDPWD/z" realpath_canonical "$OLDPWD/q"
|
for cmd in realpath_canonical; do
|
||||||
assert "$OLDPWD/y" realpath_canonical "../q/x"
|
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:
|
# And we can do non-symlink canonicalizing on the base dir of the results:
|
||||||
|
|
||||||
assert "$OLDPWD/z" realpath_canonical "../z"
|
for cmd in realpath_canonical; do
|
||||||
assert "$OLDPWD/z/foo" realpath_canonical "../z/foo"
|
assert "$OLDPWD/z" "$cmd" "../z"
|
||||||
assert "$OLDPWD/foo" realpath_canonical "../foo"
|
assert "$OLDPWD/z/foo" "$cmd" "../z/foo"
|
||||||
assert "$OLDPWD/z" realpath_canonical "../q"
|
assert "$OLDPWD/foo" "$cmd" "../foo"
|
||||||
|
assert "$OLDPWD/z" "$cmd" "../q"
|
||||||
|
done
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue