Created
December 28, 2020 20:46
-
-
Save jefferys/4bc5343d9365d8a061517255f8c72730 to your computer and use it in GitHub Desktop.
Get the directory of a path. Example use is to get a bash script's location for loading other bash scripts as modules.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Prints error messages to stderr | |
# @PARAM Concatenates parameters with IFS (default space) to form an error | |
# message. | |
# @OUT Prints error message preceeded by "ERROR: " to standard error, | |
# translating escapes. | |
# @REQUIRES: echo -e | |
function sayErr() { | |
echo -e "ERROR: $@" >&2 | |
} | |
# Figure out the directory this script is in and return it as $__ | |
# @PARAM $1 - path to obtain directory to. May be absolute or relative | |
# and may be or contain links | |
# @RET directory of "$1" as absolute path, in $__. May contain or be a link. | |
# @IO Error 1 if $1 path does not exist | |
# @IO Error 1 if $1 path is a link but can not be resolved due to a missing | |
# target or cyclical links. | |
# @REQUIRES: readlink, cd -P, dirname, pwd | |
function getMyDir() { | |
local path="$1" | |
if [[ ! -e $path && ! -L $path ]]; then | |
sayErr "Does not exist: \"$path\"." | |
return 1 | |
fi | |
# Resolve source path that is (ends in) in a symlink. Not using | |
# readlink -f as that does not work on macs. Don't care about links in path | |
local count=1000 | |
local realPath="$path" | |
while [[ -L "$realPath" && $count -gt 0 ]]; do | |
# Handle relative paths to link, need to resolve in context. | |
if [[ $realPath != /* ]]; then | |
local dir="$( dirname "$realPath" )" | |
realPath="$dir/$realPath" | |
fi | |
realPath="$(readlink "$realPath")" | |
(( count-=1 )) | |
done | |
if [[ ! -e $realPath ]]; then | |
sayErr "Path \"$path\" resolves to missing link: \"$realPath\"." | |
return 1 | |
fi | |
if [[ $count == 0 ]]; then | |
sayErr "Too many links, probably cyclical. Can't resolve \"$path\"." | |
return 1 | |
fi | |
# Resolve relative path and return. | |
# With IO capture, > dev/null needed to dump possible unwanted output. | |
__="$( cd -P "$( dirname "$SOURCE" )" >/dev/null 2>&1 && pwd )" | |
} | |
# Main entry point; called if executed | |
function main() { | |
getMyDir "$BASH_SOURCE" || exit $! | |
echo "$__" | |
} | |
# If this script is sourced, don't run main. | |
# Nothing should follow this, the exit status of main should | |
# be the exit status of the script. | |
[[ "$0" == "$BASH_SOURCE" ]] && main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment