oh-my-bash/lib/readlink.sh
2024-09-09 00:48:07 +09:00

114 lines
3.0 KiB
Bash

#! bash oh-my-bash.module
## This module provides the following function which can be used as "readlink
## -f" that can be used in any systems. The implementation is taken from
## "ble/util/readlink" from ble.sh <https://github.com/akinomyoga/ble.sh>.
##
## @fn _omb_util_readlink filename
## print the real path of the filename which is possibly a symbolic link.
##
# use _omb_util_print
_omb_module_require lib:omb-util
# use _omb_util_function_exists, _omb_util_binary_exists
_omb_module_require lib:utils
if ((_omb_bash_version >= 40000)); then
_omb_util_readlink_visited_init='local -A visited=()'
function _omb_util_readlink__visited {
[[ ${visited[$1]+set} ]] && return 0
visited[$1]=1
return 1
}
else
_omb_util_readlink_visited_init="local -a visited=()"
function _omb_util_readlink__visited {
local key
for key in "${visited[@]}"; do
[[ $1 == "$key" ]] && return 0
done
visited=("$1" "${visited[@]}")
return 1
}
fi
## @fn _omb_util_readlink__readlink path
## @var[out] link
function _omb_util_readlink__readlink {
local path=$1
if _omb_util_function_exists readlink; then
link=$(readlink -- "$path")
[[ $link ]]
elif _omb_util_binary_exists ls; then
link=$(ls -ld -- "$path") &&
[[ $link == *" $path -> "?* ]] &&
link=${link#*" $path -> "}
else
false
fi
} 2>/dev/null
## @fn _omb_util_readlink__resolve_physical_directory
## @var[in,out] path
function _omb_util_readlink__resolve_physical_directory {
[[ $path == */?* ]] || return 0
local PWD=$PWD OLDPWD=$OLDPWD CDPATH=
builtin cd -L . &&
local pwd=$PWD &&
builtin cd -P "${path%/*}/" &&
path=${PWD%/}/${path##*/}
builtin cd -L "$pwd"
return 0
}
function _omb_util_readlink__resolve_loop {
local path=$1
builtin eval -- "$_omb_util_readlink_visited_init"
while [[ -h $path ]]; do
local link
_omb_util_readlink__visited "$path" && break
_omb_util_readlink__readlink "$path" || break
if [[ $link == /* || $path != */* ]]; then
path=$link
else
_omb_util_readlink__resolve_physical_directory
path=${path%/}/$link
fi
while [[ $path == ?*/ ]]; do path=${path%/}; done
done
_omb_util_print "$path"
}
function _omb_util_readlink__resolve {
# Select implementation on the first call
_omb_util_readlink_type=
case $OSTYPE in
(cygwin | msys | linux-gnu)
# These systems provide "readlink -f".
local readlink
readlink=$(type -P readlink)
case $readlink in
(/bin/readlink | /usr/bin/readlink)
# shellcheck disable=SC2100
_omb_util_readlink_type=readlink-f
function _omb_util_readlink__resolve { readlink -f -- "$1"; } ;;
esac ;;
esac
if [[ ! $_omb_util_readlink_type ]]; then
_omb_util_readlink_type=loop
function _omb_util_readlink__resolve { _omb_util_readlink__resolve_loop "$1"; }
fi
_omb_util_readlink__resolve "$1"
}
function _omb_util_readlink {
if [[ -h $1 ]]; then
_omb_util_readlink__resolve "$1"
else
_omb_util_print "$1"
fi
}