Find installation folder for bash scripts
24 Apr 2021This is the start of a series on some bash tricks and features that I’ve developed for the bashew bash scripting micro-framework.
A problem I have spent some time on during the development of bashew, is locating the exact folder where the executing script is running from.
# a script can be called in 3 different ways:
# 1) with an explicit full path
/usr/local/bin/gettext.sh # example
# getting the folder is easy
script_folder="$(dirname "$0")"
# 2) with a explicit relative path
../install/build.sh # example
# getting the folder is a bit more complex
script_folder="$(dirname "$0")"
script_folder="$(cd -P "$script_folder" && pwd)"
# 3) without an explicit path
setver.sh # example
# this means the script can be found in the path
script_path="$(which "$0")"
script_folder="$(dirname "$script_path")"
This does however not take into account symlinks (symbolic links), and those are often used for scripts installed with a package manager, like basher. My scripts typically have nested symlinks after installation by basher.
$HOME/.basher/cellar/bin/setver
-> $HOME/.basher/cellar/packages/pforret/setver/setver
-> $HOME/.basher/cellar/packages/pforret/setver/setver.sh
These nested symlinks have to be resolved until the real physical folder has been found, a task best done by a recursive readlink
function.
This is how bashew does it:
recursive_readlink() {
[[ ! -L "$1" ]] && echo "$1" && return 0
local file_folder
local link_folder
local link_name
local symlink
file_folder="$(dirname "$1")"
[[ "$file_folder" != /* ]] &&
link_folder="$(cd -P "$file_folder" &>/dev/null && pwd)"
symlink=$(readlink "$1")
link_folder=$(dirname "$symlink")
link_name=$(basename "$symlink")
[[ -z "$link_folder" ]] &&
link_folder="$file_folder"
[[ "$link_folder" == \.* ]] &&
link_folder="$(cd -P "$file_folder" && cd -P "$link_folder" &>/dev/null && pwd)"
recursive_readlink "$link_folder/$link_name"
}
script_install_path="${BASH_SOURCE[0]}"
script_install_path=$(recursive_readlink "$script_install_path")
script_install_folder="$( cd -P "$( dirname "$script_install_path" )" && pwd )"