Bash: Resolving Symlinks to Shellscripts

Here's a way to resolve symlinks that call a bash shellscript.

The Problem

I like to be able to use something like this in my bash scripts:
SCRIPTDIR=$(dirname $0)

Which is great for a reference to where the script is, but it suffers from the problem that if you symlink to that script $0 now refers to the symlink rather than the actual script.

The Solution

The hack solution is to use the following instead:
function resolve_symlink {
    SCRIPT=$1 NEWSCRIPT=''
    until [ "$SCRIPT" = "$NEWSCRIPT" ]; do
        if [ "${SCRIPT:0:1}" = '.' ]; then SCRIPT=$PWD/$SCRIPT; fi
        cd $(dirname $SCRIPT)
        if [ ! "${SCRIPT:0:1}" = '.' ]; then SCRIPT=$(basename $SCRIPT); fi
        SCRIPT=${NEWSCRIPT:=$SCRIPT}
        NEWSCRIPT=$(ls -l $SCRIPT | awk '{ print $NF }')
    done    
    if [ ! "${SCRIPT:0:1}" = '/' ]; then SCRIPT=$PWD/$SCRIPT; fi    
    echo $(dirname $SCRIPT)
}
DIR=$(resolve_symlink $0)
echo $DIR

This updated version should fix the shortcomings of the previous version pointed out in the first comment by resolving links that are relative as well as link chains. Whilst readlink works for linux systems the script above should be portable across unixes which was the original intention.

If you can rely on python then there's an even easier way:

DIR=$(python -c "import os; print os.path.realpath(\"${0}\")")
echo $DIR

But again portability is the key.

Find any issues or have improvements to add please let me know.

Show Comments