Bash script absolute path with OS X
I am trying to obtain the absolute path to the currently running script on OS X.
I saw many replies going for readlink -f $0
. However since OS X's readlink
is the same as BSD's, it just doesn't work (it works with GNU's version).
Is there an out-of-the-box solution to this?
Solution 1:
These three simple steps are going to solve this and many other OS X issues:
- Install Homebrew
brew install coreutils
grealpath .
(3) may be changed to just realpath
, see (2) output
Solution 2:
There's a realpath()
C function that'll do the job, but I'm not seeing anything available on the command-line. Here's a quick and dirty replacement:
#!/bin/bash
realpath() {
[[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}
realpath "$0"
This prints the path verbatim if it begins with a /
. If not it must be a relative path, so it prepends $PWD
to the front. The #./
part strips off ./
from the front of $1
.
Solution 3:
I found the answer a bit wanting for a few reasons:
in particular, they don't resolve multiple levels of symbolic links, and they are extremely "Bash-y".
While the original question does explicitly ask for a "Bash script", it also makes mention of Mac OS X's BSD-like, non-GNU readlink
.
So here's an attempt at some reasonable portability (I've checked it with bash as 'sh' and dash), resolving an arbitrary number of symbolic links; and it should also work with whitespace in the path(s).
This answer was previously edited, re-adding the local
bashism. The point of this answer is a portable, POSIX solution. I have edited it to address variable scoping by changing it to a subshell function, rather than an inline one. Please do not edit.
#!/bin/sh
realpath() (
OURPWD=$PWD
cd "$(dirname "$1")"
LINK=$(readlink "$(basename "$1")")
while [ "$LINK" ]; do
cd "$(dirname "$LINK")"
LINK=$(readlink "$(basename "$1")")
done
REALPATH="$PWD/$(basename "$1")"
cd "$OURPWD"
echo "$REALPATH"
)
realpath "$@"
Hope that can be of some use to someone.
Solution 4:
A more command-line-friendly variant of the Python solution:
python -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' ./my/path