144

In a Windows command script, one can determine the directory path of the currently executing script using %~dp0. For example:

@echo Running from %~dp0

What would be the equivalent in a Bash script?

Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
Atif Aziz
  • 36,108
  • 16
  • 64
  • 74

5 Answers5

213

For the relative path (i.e. the direct equivalent of Windows' %~dp0):

MY_PATH="$(dirname -- "${BASH_SOURCE[0]}")"
echo "$MY_PATH"

For the absolute, normalized path:

MY_PATH="$(dirname -- "${BASH_SOURCE[0]}")"            # relative
MY_PATH="$(cd -- "$MY_PATH" && pwd)"    # absolutized and normalized
if [[ -z "$MY_PATH" ]] ; then
  # error; for some reason, the path is not accessible
  # to the script (e.g. permissions re-evaled after suid)
  exit 1  # fail
fi
echo "$MY_PATH"
Mario Palumbo
  • 693
  • 8
  • 32
vladr
  • 65,483
  • 18
  • 129
  • 130
  • 1
    what is the problem on your mac bash? works just fine over here on Cygwin, Linux, Solaris, etc., and it must also work on mac – vladr Mar 10 '09 at 14:15
  • it only gives the relative path though –  Mar 10 '09 at 14:16
  • $0 gives "-bash" and then dirname argue about "-b" option. – Mykola Golubyev Mar 10 '09 at 14:19
  • @Mykola, This is because you are running it directly at the command prompt, not from a script, and because mac is anal about what $0 is at the command prompt (the above works at the command prompt on all other platforms BTW.) – vladr Mar 10 '09 at 14:20
  • If you do "exec /bin/bash" you'll then populate $0 with what you want. – Jeremy L Mar 10 '09 at 14:20
  • If this is bash specifically I'd use `$()` over `\`\``. The only thing that \` has better is POSIX-compatibility. – Daenyth Jul 14 '10 at 02:54
  • 2
    Within bash you can also use `$BASH_SOURCE`. From [this post](http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in). – JamesThomasMoon May 01 '13 at 17:12
  • 5
    $0 would be OK in most cases, some exceptions are, for instance, when the script you're executing is aliased (through alias in .bash_profile). You should really use $BASH_SOURCE variable, instead of $0. – Dmitri Sologoubenko Feb 27 '15 at 12:45
  • 4
    Doesn't work for me when I execute a script via a symlink. Is there a variant which will determine the fully-resolved script directory? EDIT: `$(dirname $(readlink $0))` seems to work – shaunc Sep 22 '15 at 04:32
  • 3
    Using `$0` does not work when the script is run using `source script` or `. script`; the name of the script is not available. – Christopher Schultz Oct 01 '16 at 00:27
  • @christopher see @james's or @Dmitri's comment about using `$BASH_SOURCE` – northern-bradley Jan 14 '21 at 18:39
  • `%dp0` gives the normalized absolute path. – Shayan Toqraee Feb 05 '21 at 18:44
  • This answer is partially incorrect, because if you are in the user folder and your script is in the `Documents` folder, if you call it so `. Documents/test.sh`, the output will be `.`, If you call it so `./Documents/test.sh`, the output will be correct `Documents`, so the exact solution is: `MY_PATH="$(dirname -- "${BASH_SOURCE[0]}")"` – Mario Palumbo Nov 07 '22 at 00:25
30

Assuming you type in the full path to the bash script, use $0 and dirname, e.g.:

#!/bin/bash
echo "$0"
dirname "$0"

Example output:

$ /a/b/c/myScript.bash
/a/b/c/myScript.bash
/a/b/c

If necessary, append the results of the $PWD variable to a relative path.

EDIT: Added quotation marks to handle space characters.

Alex Reynolds
  • 95,983
  • 54
  • 240
  • 345
  • 1
    @Rothko, your solution will fail if $0 contains blanks. – vladr Mar 10 '09 at 14:25
  • 3
    Within bash you can also use `$BASH_SOURCE`. From [this post](http://stackoverflow.com/questions/59895/can-a-bash-script-tell-what-directory-its-stored-in). – JamesThomasMoon May 01 '13 at 17:10
11

Contributed by Stephane CHAZELAS on c.u.s. Assuming POSIX shell:

prg=$0
if [ ! -e "$prg" ]; then
  case $prg in
    (*/*) exit 1;;
    (*) prg=$(command -v -- "$prg") || exit;;
  esac
fi
dir=$(
  cd -P -- "$(dirname -- "$prg")" && pwd -P
) || exit
prg=$dir/$(basename -- "$prg") || exit 

printf '%s\n' "$prg"
Dimitre Radoulov
  • 27,252
  • 4
  • 40
  • 48
  • brilliant works for me on Mac OSX the other approaches in this question did not. – ams Mar 06 '12 at 00:52
  • +1 for dealing with script invocation via `$PATH` search; however, the above **is NOT POSIX**. It will only work with `bash`. Use `which` instead of `command` and backticks instead of `$(...)` is this has to run under other, older shells. – vladr Nov 17 '12 at 19:25
  • 6
    Hi @vladr, the above code is POSIX! If I understand correctly, what you mean is that the code won't run with the old Bourne shell (/bin/sh on Solaris < 11 for instance), but that has nothing to do with POSIX. – Dimitre Radoulov Nov 18 '12 at 09:13
  • 1
    @DimitreRadoulov sorry yes I meant the lowest common-denominator POSIX, for most portability, i.e. POSIX.1. Technically yes, any POSIX.2 shell as well as old `ksh` etc., not just `bash`, will run the above, but quite a few people out there are still on Solaris 10 (end-of-support is 2018, quite a few more years to go), and some even run old AIX and HP-UX. – vladr Nov 18 '12 at 14:57
  • 3
    @vladr, Bourne shell is not POSIX compliant and it predates the POSIX standards. The standardized user command line and scripting interface of POSIX.1 were based on the Korn Shell. As far as I know all commercial Unices offer a POSIX compliant shell (it's /usr/xpg4/bin/sh on Solaris for example). – Dimitre Radoulov Nov 18 '12 at 21:20
6
echo Running from $(dirname "$0")
Matthias Braun
  • 32,039
  • 22
  • 142
  • 171
xagyg
  • 9,562
  • 2
  • 32
  • 29
3

Vlad's code is overquoted. Should be:

MY_PATH=`dirname "$0"`
MY_PATH=`( cd "$MY_PATH" && pwd )`
Poor Yorick
  • 229
  • 1
  • 4
  • 4