Skip to content

Instantly share code, notes, and snippets.

@hilbix
Last active February 27, 2024 22:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hilbix/1ec361d00a8178ae8ea0 to your computer and use it in GitHub Desktop.
Save hilbix/1ec361d00a8178ae8ea0 to your computer and use it in GitHub Desktop.
Calculate relative path in BASH
: relpath A B
# Calculate relative path from A to B, returns true on success
# Example: ln -s "$(relpath "$A" "$B")" "$B"
relpath()
{
local X Y A
# We can create dangling softlinks
X="$(readlink -m -- "$1")" || return
Y="$(readlink -m -- "$2")" || return
X="${X%/}/"
A=""
# See http://stackoverflow.com/questions/2564634/bash-convert-absolute-path-into-relative-path-given-a-current-directory
while Y="${Y%/*}"
[ ".${X#"$Y"/}" = ".$X" ]
do
A="../$A"
done
X="$A${X#"$Y"/}"
X="${X%/}"
echo "${X:-.}"
}
# example use of relpath.inc, instead of "ln -vs A B" do "lns A B"
# idempotent, so no writes if everything is already OK
. "$(dirname "$0")/_relpath.inc"
OOPS()
{
echo "OOPS: $*" >&2
exit 1
}
NOTE()
{
echo "NOTE: $*" >&2
}
lns()
{
local R
if [ -L "$2" ]
then
# Check if both links are the same file
[ ".$(readlink -m -- "$1")" = ".$(readlink -m -- "$2")" ] && return
NOTE "replacing $2"
rm -vf "$2"
else
[ ! -e "$2" ] || OOPS "$2 exists and is no soflink"
NOTE "creating $2"
fi
# Note: $2 must not exist, else relpath fails!
R="$(relpath "$1" "$2")" || OOPS "relpath '$1' '$2'"
ln -vs "$R" "$2"
}
lns "$@"
@hilbix
Copy link
Author

hilbix commented Nov 28, 2014

Renamed relpath.inc to _relpath.inc to have GitHub list the correct filename in GIST.

Note that lns is the shell function name, the shell script name is ./linkit.sh A B

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment