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_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 thatBASH_SOURCE
is 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
cd
ing into../script-dir
, swallowing all output by redirecting stdout to/dev/null
and 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.sh
when the “real” script lives at/home/user/script-dir/super-script.sh
), this will return/home/user/other-dir
.