Posted By: Anonymous
I have a Bash script that needs to know its full path. I’m trying to find a broadly-compatible way of doing that without ending up with relative or funky-looking paths. I only need to support Bash, not sh, csh, etc.
What I’ve found so far:
The accepted answer to Getting the source directory of a Bash script from within addresses getting the path of the script via
dirname $0, which is fine, but that may return a relative path (like
.), which is a problem if you want to change directories in the script and have the path still point to the script’s directory. Still,
dirnamewill be part of the puzzle.
The accepted answer to Bash script absolute path with OS X (OS X specific, but the answer works regardless) gives a function that will test to see if
$0looks relative and if so will pre-pend
$PWDto it. But the result can still have relative bits in it (although overall it’s absolute) — for instance, if the script is
tin the directory
/usr/binand you’re in
/usrand you type
bin/../bin/tto run it (yes, that’s convoluted), you end up with
/usr/bin/../binas the script’s directory path. Which works, but…
readlinksolution on this page, which looks like this:
# Absolute path to this script. /home/user/bin/foo.sh SCRIPT=$(readlink -f $0) # Absolute path this script is in. /home/user/bin SCRIPTPATH=`dirname $SCRIPT`
readlinkisn’t POSIX and apparently the solution relies on GNU’s
readlinkwhere BSD’s won’t work for some reason (I don’t have access to a BSD-like system to check).
So, various ways of doing it, but they all have their caveats.
What would be a better way? Where “better” means:
- Gives me the absolute path.
- Takes out funky bits even when invoked in a convoluted way (see comment on #2 above). (E.g., at least moderately canonicalizes the path.)
- Relies only on Bash-isms or things that are almost certain to be on most popular flavors of *nix systems (GNU/Linux, BSD and BSD-like systems like OS X, etc.).
- Avoids calling external programs if possible (e.g., prefers Bash built-ins).
- (Updated, thanks for the heads up, wich) It doesn’t have to resolve symlinks (in fact, I’d kind of prefer it left them alone, but that’s not a requirement).
SCRIPTPATH="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
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).
cd and before
"$0" are in case the directory starts with a