I've often wanted to make a script perform an action on some resource that's located relative to the
script.E.g., run clang-format
on all of the C++ files in a repository, without running
clang-format
on any generated files, or submodule content, and without the restriction
that you need to run the script from the repository root.
SOURCE="${BASH_SOURCE[0]}"
SCRIPT_DIRECTORY="$(cd "$(dirname "$SOURCE")" >/dev/null && pwd)"
But if there are symlinks that you want to resolve, you need to resolve them until
$SOURCE
is no longer a symlink.This seems like a pretty niche thing that you might not want to do. I found in helpful in my
~/.bashrc
because I clone my
dotfiles repository to
~/.config/dotfiles/
and symlink the contents into my home directory.
SOURCE="${BASH_SOURCE[0]}"
# resolve $SOURCE until the file is no longer a symlink
while [ -h "$SOURCE" ]; do
SCRIPT_DIRECTORY="$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)"
SOURCE="$(readlink "$SOURCE")"
# if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
[[ $SOURCE != /* ]] && SOURCE="$SCRIPT_DIRECTORY/$SOURCE"
done
SCRIPT_DIRECTORY="$(cd -P "$(dirname "$SOURCE")" >/dev/null 2>&1 && pwd)"
Then take the path to the script directory, and resolve the relative path to whatever resource you're interested in.
RELATIVE_ASSET="$SCRIPT_DIRECTORY/../relative/path/to/asset/"
# Resolve $RELATIVE_ASSET to an absolute path. May or may not be necessary.
ABSOLUTE_ASSET="$(readlink --canonicalize --no-newline "$RELATIVE_ASSET")"
If your script is in a Git repository (and you expect it to be executed from a Git repository), you can also use
REPO_DIRECTORY=$(git rev-parse --show-toplevel)