I’m often having to look up “how do I get the directory of a script in bash?” Therefore, documenting my findings so (a) it can hopefully be of help to someone else and (b) it can at least serve as a reference for me in the future.
tl;dr
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
What is this thing doing?
For example, say there’s a script at /home/user/script-dir/super-script.sh and it is
being invoked from the /home/user/other-dir directory using bash ../script-dir/super-script.sh. In other words:
$ pwd
/home/user/other-dir
$ bash ../script-dir/super-script.sh
...
This breaks down as:
$BASH_SOURCE[0]->../script-dir/super-script.sh- The
BASH_SOURCEvariable contains the names of the script files. The first element is the current script. - Note that just using
$BASH_SOURCE(without the[0]) does work since bash will return the first member of an array when an index number is not provided. However, for the cost of 3 bytes, I find the extra clarity thatBASH_SOURCEis an array and we’re getting the first element is valuable.
- The
dirname "${BASH_SOURCE[0]}"->../script-dir- Basic “remove the last path component” command. Of note, the path is still relative at this point.
cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd->/home/user/script-dir- This turns the relative path into an absolute path by
cding into../script-dir, swallowing all output by redirecting stdout to/dev/nulland stderr to stdout (which is going to/dev/null). Oncecd’d we print the current directory.
- This turns the relative path into an absolute path by
Known Caveats
- If the script is invoked via a symlink (e.g. running
/home/user/other-dir/symlinked-script.shwhen the “real” script lives at/home/user/script-dir/super-script.sh), this will return/home/user/other-dir.