26

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

1

Another approach:

# Install.
brew install coreutils

# Use the GNU variant.
grealpath --help

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .