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: