27

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?

3

4 Answers 4

23

I cheat and use perl for this very thing:

#!/bin/bash
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.

4
  • 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? Commented Jul 13, 2009 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.) Commented Jul 13, 2009 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. Commented Jul 14, 2009 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. Commented Jul 3, 2013 at 18:47
33
#!/usr/bin/env bash
scriptDir="$(cd "$(dirname "$0")" && pwd -P)"
5
  • Works in MacOSX too. Commented Jan 14, 2016 at 12:10
  • 1
    This is super! There are many other over-complicated answers floating around. Commented May 28, 2016 at 9:21
  • 3
    This only works for files in a symlinked directory, not for symlinked files in general Commented Aug 25, 2016 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. Commented Apr 12, 2017 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) Commented Apr 12, 2017 at 18:43
3

Another approach:

# Install.
brew install coreutils

# Use the GNU variant.
grealpath --help
1

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

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

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

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.