This does what realpath from coreutils does, but works without it. Requires readlink instead. Recursively resolve all symlinks at the specified path and then print the final, absolute path.

#
# Print the absolute path of the target path. Note that the path must be a
# real path to a file or directory or else this will fail.
#
# $1: the target file or directory
#
# https://github.com/dansimau/bashlib/blob/master/bash.sh#L112
absolute_path() {
    local path=$1

    if [ "$path" == "." ]; then
        echo "$(pwd)"
    elif [ "$path" == ".." ]; then
        echo "$(dirname "$(pwd)")"
    else
        path="$(
            cd "$(dirname "$1")"
            pwd
        )/$(basename "$1")"
        # Replace double slashes, happens when we're operating at the root
        echo "${path/\/\///}"
    fi
}

#
# Recursively resolve symlinks
#
# This does what `realpath` from coreutils does but works without it. Requires
# readlink instead.
#
# Recursively resolve all symlinks at the specified path and then print the
# final, absolute path.
#
# https://github.com/dansimau/bashlib/blob/master/bash.sh#L139
resolve_symlinks() {
    (
        local path=$1

        while [ -L "$path" ]; do
            dir="$(dirname "$(absolute_path "$path")")"
            cd "$dir"
            path=$(readlink "$path")
        done

        echo "$(absolute_path "$path")"
    )
}