Recently I came into the situation where I want to get the location of the current bash script, and then read and save files using relative paths. This can be quite useful, considering I need to deploy some scripts together with data and log folders across different machines, and want to make it a bit more portable. This one-liner does the work:
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
We can break it down to:
pushd "$( dirname "${BASH_SOURCE[0]}" )"
DIR="$PWD"
popd
Here, BASH_SOURCE[0]
is the relative path to the script being executed or sourced. Note the difference between BASH_SOURCE[0]
and $0
: when a script is sourced, BASH_SOURCE[0]
will be the path to the script, while $0
will be the path to the bash executable. Here is an example to show this:
ubuntu@xenial:~$ cat test/b.bash
echo $0
echo $BASH_SOURCE
ubuntu@xenial:~$ bash test/b.bash
test/b.bash
test/b.bash
ubuntu@xenial:~$ source test/b.bash
/bin/bash
test/b.bash
In this case, I do not plan to source this script, so I can safely replace BASH_SOURCE[0]
with $0
.
Next, dirname
gives the directory name to the script. This coreutils
command strips the last non-slash component from a string, and in case the string contains no slash, it returns .
. Here is an example:
ubuntu@xenial:~$ dirname Projects/test/file_a
Projects/test
ubuntu@xenial:~$ dirname Projects/test/dir_c
Projects/test
ubuntu@xenial:~$ dirname Projects/test/dir_c/
Projects/test
ubuntu@xenial:~$ dirname Projects/
.
Now this one-liner should be easy to understand: cd
to the directory which contains the current script being executed (or sourced), get the working directory with pwd
, and save it in a variable called DIR
.
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"