25

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?

Huxi
  • 361
  • 1
  • 4
  • 6
  • 1
    See this question over on SO: http://stackoverflow.com/questions/799679/programatically-retrieving-the-absolute-path-of-an-os-x-command-line-app – Telemachus Jul 13 '09 at 21:21
  • 3
    And this one: http://stackoverflow.com/questions/1055671/how-can-i-get-the-behavior-of-gnus-readlink-f-on-a-mac – Telemachus Jul 13 '09 at 21:23
  • Even more options: http://stackoverflow.com/questions/7665/how-to-resolve-symbolic-links-in-a-shell-script – Gerhard Burger Aug 25 '16 at 05:07

4 Answers4

31
#!/usr/bin/env bash
scriptDir="$(cd "$(dirname "$0")" && pwd -P)"
Hauke Laging
  • 5,285
  • 2
  • 24
  • 40
jhclark
  • 540
  • 5
  • 6
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.

ericslaw
  • 1,572
  • 2
  • 13
  • 15
  • 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 02: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 03 '13 at 18:47
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.

Humberto Castellon
  • 879
  • 1
  • 7
  • 17
Oliver
  • 240
  • 2
  • 7
1

Another approach:

# Install.
brew install coreutils

# Use the GNU variant.
grealpath --help
FMc
  • 111
  • 3