Bash: Get Current Script Directory

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:

  1. $BASH_SOURCE[0] -> ../script-dir/super-script.sh
    • The BASH_SOURCE variable 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 that BASH_SOURCE is an array and we’re getting the first element is valuable.
  2. dirname "${BASH_SOURCE[0]}" -> ../script-dir
    • Basic “remove the last path component” command. Of note, the path is still relative at this point.
  3. 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/null and stderr to stdout (which is going to /dev/null). Once cd’d we print the current directory.

Known Caveats

  1. If the script is invoked via a symlink (e.g. running /home/user/other-dir/symlinked-script.sh when the “real” script lives at /home/user/script-dir/super-script.sh), this will return /home/user/other-dir.