19

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?

19

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.

  • 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
27
#!/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 – Gerhard Burger 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. – Binary Phile 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) – Binary Phile Apr 12 '17 at 18:43
0

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.

0

Another approach:

# Install.
brew install coreutils

# Use the GNU variant.
grealpath --help

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.