ksh(1) / bash(1) : HOWTO: get the full path to the script directory

In ksh(1) and bash(1) it is possible to get arg0 of the command line using $0.

Sometimes you need to know the folder/directory from which the script was run. $0 can help us here. $0 will contain the command used to invoke the script, for example

/path/to/myscript.sh
./myscript.sh
relative/path/to/myscript.sh
../../somewhere/in/the/file/system/is/myscript.sh

However, non of these (bar the first example) can actually tell us the full path to the directory from which the script was executed. What we need to do is turn the relative paths into absolute ones.

To do this, first recognize that the at the beginning of execution of the script, the path to the script is relative to the current directory. Because of this we can cd(1) to the path part of $0 then use $PWD to obtain the full path of that directory. We need to do this in such a way that it does not disturb the current directory.

The following code does just this (place this code just after the #!/bin/bash line):

SCRIPT_DIR=`( cd "${0%/*}" ; echo $PWD )`

What this does is it takes $0, removes everything after the last / and cd’s to that directory in a sub-shell, then outputs $PWD which is captured and stored in the variable SCRIPT_DIR.

A variation of this which will also work in sh(1)

_p=`dirname "$0"`; SCRIPT_DIR=`( cd "$_p" ; pwd )`; unset _p

UPDATE: Here is a much simpler way to achieve this:-

SCRIPT_DIR=$( cd $(dirname "$0") ; pwd )

About austinfrance

Technical Developer @ RedSky IT / Explorer Software
This entry was posted in Uncategorized. Bookmark the permalink.

10 Responses to ksh(1) / bash(1) : HOWTO: get the full path to the script directory

  1. mpersic says:

    Unless your script is being dotted in:

    $ set -x
    $ echo ‘echo dollar zero is $0’ > bar
    + echo echo dollar zero is $0
    + 1> bar
    $ chmod +x bar
    + chmod +x bar
    $ ./bar
    + ./bar
    dollar zero is ./bar
    $. ./bar
    + . ./bar
    + echo dollar zero is -ksh
    dollar zero is -ksh

  2. mpersic says:

    Use $_ instead:

    $ cat bar
    + cat bar
    echo dollar under is $_
    echo dollar zero is $0

    $ ./bar
    + ./bar
    dollar under is ./bar
    dollar zero is ./bar

    $ . ./bar
    + . ./bar
    + echo dollar under is ./bar
    dollar under is ./bar
    + echo dollar zero is -ksh
    dollar zero is -ksh

  3. austinfrance says:

    $_ is the last word of the previous command. It just happens to be from the ksh command line when referenced before any other command.

    $ cat foo
    #!/bin/bash
    echo $0
    echo something else
    echo $_

    $ cat bar
    #!/bin/bash
    . ./foo

    $ ksh foo
    foo
    something else
    else

    $ ksh bar
    bar
    something else
    /bin/ksh

    $_ is giving unpredictable results in this scenario, and $0 works in bash and ksh at least the versions on my machine (fc14)

    • $0 does not work if your script is sourced in. $_ will work IFF you capture it’s value in the very first statement in your script. I should have made that clear. It’s kind of like using $? – if your don’t capture it right after the statement your referencing, all bets are off.

      • John says:

        Thank you Mathew ! I was testing this and all I got was a one (1) for a sourced in call. capturing it in the very first statement did the trick.

      • John says:

        Ooops scratch that. Even when captured at the start of the script, $_ doesn’t work when the script is source-called with an option (it equals the option). e.g.,

        . bar/foo
        ($_ will equal bar/foo)

        . bar/foo gen
        ($_ will equal gen)

  4. austinfrance says:

    I tested $_ just on its own and it does appear to work (tested in bash and ksh on linux). I then did the same test for $0 again.

    $ cat foo
    #!/bin/ksh
    echo $0
    $ cat bar
    #!/bin/ksh
    . ./foo
    $ ./foo
    ./foo
    $ ./bar
    ./bar

    If I replace #!/bin/ksh with #!/bin/bash I get the same result. $0 seems to be working fine.

  5. mpersic says:

    Try
    $ . ./foo
    and
    $ . ./bar

  6. mpersic says:

    And after further experimentation this morning I discovered $_ is even trickier. Instead of doing
    . ./some_profile
    I did
    X=./some_profile
    . $X
    and $_ in some_profile was ‘X’ not ‘some_profile’. It’s not perfect – you need to know what you’re doing to use it.

  7. mpersic says:

    I just got your result where $_ is the previous command and not my file. This happens if the call to the containing script is in a script of commands itself. I have to withdraw $_ as a useful solution.

Leave a comment