Reliable way for a Bash script to get the full path to itself

I just had to revisit this issue today and found Get the source directory of a Bash script from within the script itself:

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

There's more variants at the linked answer, e.g. for the case where the script itself is a symlink.


The simplest way that I have found to get a full canonical path in Bash is to use cd and pwd:

ABSOLUTE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"

Using ${BASH_SOURCE[0]} instead of $0 produces the same behavior regardless of whether the script is invoked as <name> or source <name>.


Here's what I've come up with (edit: plus some tweaks provided by sfstewman, levigroker, Kyle Strand, and Rob Kennedy), that seems to mostly fit my "better" criteria:

SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"

That SCRIPTPATH line seems particularly roundabout, but we need it rather than SCRIPTPATH=`pwd` in order to properly handle spaces and symlinks.

The inclusion of output redirection (>/dev/null 2>&1) handles the rare(?) case where cd might produce output that would interfere with the surrounding $( ... ) capture. (Such as cd being overridden to also ls a directory after switching to it.)

Note also that esoteric situations, such as executing a script that isn't coming from a file in an accessible file system at all (which is perfectly possible), is not catered to there (or in any of the other answers I've seen).

The -- after cd and before "$0" are in case the directory starts with a -.


I'm surprised that the realpath command hasn't been mentioned here. My understanding is that it is widely portable / ported.

Your initial solution becomes:

SCRIPT=$(realpath "$0")
SCRIPTPATH=$(dirname "$SCRIPT")

And to leave symbolic links unresolved per your preference:

SCRIPT=$(realpath -s "$0")
SCRIPTPATH=$(dirname "$SCRIPT")

Tags:

Bash

Path