How a BASH Script Can Find Its Own Location
Most foolproof method I'm aware of is the following:
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd && echo x)"
SCRIPTDIR="${SCRIPTDIR%x}"
or if you're not worried about newlines at the end of your directory names:
SCRIPTDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
How does this work? In the first example you cd
into the path portion of the script that was executed (e.g. ./foo
of ./foo/bar.sh
or /tmp
of /tmp/bar.sh
) which dirname
of ${BASH_SOURCE[0]}
provides -- ${BASH_SOURCE[0]}
is the top of the stack of source files (e.g. scripts) being called, that is, the current script being executed. Basically this applies the possibly relative pathname used to call the script to the current working directory to get the subshell into the absolute directory path of the script.
After that running pwd
returns the current working directory of the subshell, which is now the parent script's location. An "x
" is tacked on the end to prevent any trailing carriage returns or line feeds from being lost (why are you storing your script in a directory with a carriage return at the end of its name?). Then by using some BASH
parameter expansion tricks the "x
" is removed from the end of the SCRIPTDIR
variable value.
Just a note, if the script's path involves symlinks SCRIPTDIR
will be the path with symlinks (this includes if the script name is a symlink). If you want the actual non-symlinked path you'll need to do some more work -- unless the version of readlink
on your system supports the --canonicalize
option in which case you're golden -- just run readlink --canonicalize
against $SCRIPTDIR
. The option --canonicalize
is sometimes called -f
, but on OSX, for example, the -f
from readlink
is not what you're looking for. You're left with the hard way:
SCRIPT="${BASH_SOURCE[0]}" # get the location of the script relative to the cwd
while [ -L "$SCRIPT" ]; do # while the filename in $SCRIPT is a symlink
DIR="$( cd -P "$( dirname "$SCRIPT" )" && pwd )" # similar to above, but -P forces a
# change to the physical not symbolic directory
SCRIPT="$(readlink "$SCRIPT")" # value of symbolic link
[[ $SCRIPT != /* ]] && SCRIPT="$DIR/$SCRIPT" # if $SCRIPT is relative (doesn't begin
# with /), resolve relative path where symlink lives
done
DIR="$( cd -P "$( dirname "$SCRIPT" )" && pwd )"