Skip to content

Instantly share code, notes, and snippets.

@takahisa
Created September 11, 2023 09:26
Show Gist options
  • Save takahisa/763aa2482cf58acb71a13cb7f08bce0f to your computer and use it in GitHub Desktop.
Save takahisa/763aa2482cf58acb71a13cb7f08bce0f to your computer and use it in GitHub Desktop.
abspath ⇔ relpath (bash)
function abspath() {
if [[ ! -r "${1}" ]]; then
echo >&2 "No such file or directory: $1"
return 1
fi
if [[ -d "${1}" ]]; then
echo "$(cd "${1}" || return 1; pwd)"
else
echo "$(cd "$(dirname "${1}")" || return 1; pwd)/$(basename "${1}")"
fi
}
function relpath() {
if [[ ! -r "${1}" ]]; then
echo >&2 "No such file or directory: $1"
return 1
fi
if [[ ! -r "${2}" ]]; then
echo >&2 "No such file or directory: $2"
return 1
fi
local relative_path=""
local p q pi qi pj qj
p="$(abspath "${1}")"
q="$(abspath "${2}")"
pi="$(get_distance_from_root_directory "${p}")"
qi="$(get_distance_from_root_directory "${q}")"
pj="${pi}"
qj="${qi}"
# Calculate the common part from two given paths.
while [[ "${p}" != "${q}" ]]; do
if [[ "${pj}" == "${qj}" ]]; then
relative_path="$(basename "${q}")/${relative_path}"
p="$(dirname "${p}")"
q="$(dirname "${q}")"
pj="$(( pj - 1 ))"
qj="$(( qj - 1 ))"
elif (( pj >= qj )); then
p="$(dirname "${p}")"
pj="$(( pj - 1 ))"
else
relative_path="$(basename "${q}")/${relative_path}"
q="$(dirname "${q}")"
qj="$(( qj - 1 ))"
fi
done
if [[ "${pi}" == "${pj}" ]]; then
relative_path="./${relative_path}"
fi
for _ in $(seq "$(( pi - pj ))"); do
relative_path="../${relative_path}"
done
echo "${relative_path%/}"
}
function get_distance_from_root_directory() {
local distance="0"
local p q
p="$(abspath "${1}")"
q="$(dirname "${p}")"
while [[ "${p}" != "${q}" ]]; do
distance="$(( distance + 1 ))"
p="${q}"
q="$(dirname "${q}")"
done
echo "${distance}"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment