I'd like to retrieve the absolute file name of the script file that's currently executed. Links should be resolved, too.

On Linux, this seems to be done like this:

$(readlink -mn "$0")

but readlink seems to work very differently on Mac OS X.

I've read that this is done using

$(realpath $0)

in BSD but that doesn't work, either. Mac OS X does not have realpath.

Any idea?


I cheat and use perl for this very thing:

dirname=`perl -e 'use Cwd "abs_path";print abs_path(shift)' $0`
echo $dirname

You'd think I'd just write the entire script in perl, and often I do, but not always.

  • This works, thanks a lot. I'll give you an upvote as soon as I can. Does anyone have a "pure shell" way of doing this?
    – Huxi
    Jul 13 '09 at 21:17
  • 1
    I'm afraid this is as good as it gets. (Given the many multiple-line "pure shell" hacks one can find on Google.)
    – Arjan
    Jul 13 '09 at 21:34
  • another possibility (though ugly) is to traverse the '..' path, memorizing (thru recursion or an array) until '..' returns the same file you just had (ie: you are at the top), then come back assembling the path as you go. I've seen Legato's Networker backup software doing this during strace as a method of obtaining a 'true' path (but perhaps not absolute). But it would be a lot more code than the above.
    – ericslaw
    Jul 14 '09 at 2:56
  • Not sure why someone modifed the code to use $1 instead of $0. Isn't $1 the first arg to the bash script? I wanted the path to the executing bash script, not it's first argument.
    – ericslaw
    Jul 3 '13 at 18:47
#!/usr/bin/env bash
scriptDir="$(cd "$(dirname "$0")" && pwd -P)"
  • Works in MacOSX too.
    – Alexar
    Jan 14 '16 at 12:10
  • 1
    This is super! There are many other over-complicated answers floating around.
    – Jason S
    May 28 '16 at 9:21
  • 3
    This only works for files in a symlinked directory, not for symlinked files in general Aug 25 '16 at 5:09
  • 1
    It's also helpful to unset -v CDPATH prior to the cd since cd can cause unwanted output if CDPATH is set. Apr 12 '17 at 18:33
  • To deal with at least a single layer of symlinking of the file, you can also test in a compatible way with readlink (macs don't have -f): scriptDir=$(unset -v CDPATH; cd "$(dirname "$(readlink "$BASH_SOURCE" || echo "$BASH_SOURCE)")" && pwd -P) Apr 12 '17 at 18:43

Another approach:

# Install.
brew install coreutils

# Use the GNU variant.
grealpath --help

This handles combos of symlinks, and it works on files and folders:

#!/usr/bin/env bash
    if ! pushd $1 &> /dev/null; then 
        pushd ${1##*/} &> /dev/null
        echo $( pwd -P )/${1%/*}
        pwd -P
    popd > /dev/null

But it does not support realpath's --relative-to. This would require the conversion described here.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.