151

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?

0

5 Answers 5

223

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"
Sign up to request clarification or add additional context in comments.

14 Comments

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
Within bash you can also use $BASH_SOURCE. From this post.
$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.
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
Using $0 does not work when the script is run using source script or . script; the name of the script is not available.
|
31

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.

2 Comments

@Rothko, your solution will fail if $0 contains blanks.
Within bash you can also use $BASH_SOURCE. From this post.
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"

5 Comments

brilliant works for me on Mac OSX the other approaches in this question did not.
+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.
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.
@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, 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).
6
echo Running from $(dirname "$0")

Comments

3

Vlad's code is overquoted. Should be:

MY_PATH=`dirname "$0"`
MY_PATH=`( cd "$MY_PATH" && pwd )`

3 Comments

Your second line has an extra double-quote character.
The overquoting was needed on older Solaris versions, which were still being used at the time of the original post.
Surely the parentheses are unnecessary even on Solaris?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.