tags:

views:

30728

answers:

28

How do I get the path of the directory in which a bash script is located FROM that bash script.

For instance, lets say I want to use a bash script as a launcher for another application. I want to change working directory to the one where the bash script is located so I can operate on the files in that directory like so:

$ ./application

A: 

Are you perhaps looking for 'pwd'?

Assuming that pwd returns the directory of the script and not where you run the script from:

#!/bin/bash
$orpath = 'set original path';
$path = `pwd`;
if [ $path = $orpath]
   then
   # do whatever
fi

EDIT: Disregard this post... it seems my assumptions are faulty.

apandit
pwd won't give him what he wants if you are not running the script from the directory it is actually in
matt b
Your assumption is faulty.
David Locke
A: 
`pwd`

(remember the backtics) will get you the current directory from within your bash script.

But I would use the $PWD variable instead.

Jason Navarrete
+1  A: 

You will probably need to use something with 'basename' and then grep out the path from the full program name.

PROG= `basename $0 ` should get you started.

The problem with using 'pwd' is that will only give your the current working directory. If your script changes working directories, this will not give you the directory where the script is located.

Scott Dorman
A: 

Not 100% sure I'm following you (it's late on Friday!), but can you use

dirname $0
AndrewJFord
+72  A: 

Use dirname:

#!/bin/bash
echo "The script you are running has basename `basename $0`, dirname `dirname $0`"
echo "The present working directory is `pwd`"

using pwd alone will not work if you are not running the script from the directory it is contained in.

[[email protected] ~]$ pwd
/home/matt
[[email protected] ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[[email protected] ~]$ cd /tmp
[[email protected] tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp
matt b
For portability beyond bash, $0 may not always be enough. You may need to substitute "type -p $0" to make this work if the command was found on the path.
Darron
@Darron: you can only use `type -p` if the script is executable. This can also open a subtle hole if the script is executed using `bash test2.sh` and there is another script with the same name executable somewhere else.
D.Shawley
@Darron: but since the question is tagged `bash` and the hash-bang line explicitly mentions `/bin/bash` I'd say it's pretty safe to depend on bashisms.
Joachim Sauer
+11  A: 

You can use $BASH_SOURCE

#!/bin/bash

scriptdir=`dirname $BASH_SOURCE`

Note that you need to use #!/bin/bash and not #!/bin/sh since its a bash extension

Mr Shark
When I do `./foo/script`, then `$(dirname $BASH_SOURCE)` is `./foo`.
Till
+8  A: 

I don't think this is as easy as others have made it out to be. pwd doesn't work, as the current dir is not necessarily the directory with the script. $0 doesn't always have the info either. Consider the following three ways to invoke a script.

./script

/usr/bin/script

script

In the first and third ways $0 doesn't have the full path info. In the second and third, pwd do not work. The only way to get the dir in the third way would be to run through the path and find the file with the correct match. Basically the code would have to redo what the OS does.

One way to do what you are asking would be to just hardcode the data in the /usr/share dir, and reference it by full path. Data shoudn't be in the /usr/bin dir anyway, so this is probably the thing to do.

+1  A: 
#!/bin/sh
PRG="$0"

# need this for relative symlinks
while [ -h "$PRG" ] ; do
   PRG=`readlink "$PRG"`
done

scriptdir=`dirname "$PRG"`
+3  A: 

pwd can be used to find the current working directory, and dirname to find the directory of a particular file (command that was run, is $0, so dirname $0 should give you the directory of the current script).

However, dirname gives precisely the directory portion of the filename, which more likely then not is going to be relative to the current working directory. If your script needs to change directory for some reason, then the output from dirname becomes meaningless.

I suggest the following:

#!/bin/bash

reldir=`dirname $0`
cd $reldir
directory=`pwd`

echo "Directory is $directory"

This way, you get an absolute, rather then relative directory.

Since the script will be run in a seperate bash instance, there is no need to restore the working directory afterwards, but if you do want to change back in your script for some reason, you can easily assign the value of pwd to a variable before you change directory, for future use.

Although just

cd `dirname $0`

solves the specific scenario in the question, I find having the absolute path to more more useful generally.

SpoonMeiser
dogbane
A: 

If $0 is an absolute path then you are done, and an alternative to dirname is just iterating through the paths defined in $PATH. The cd trick to make the path absolute can be combined with pushd/popd. Another option for an absolute path is to prefix the path with pwd if the path from dirname/basename is relative. Keep in mind that $0 can be supplied by the user and hence should not be trusted.

/Allan

Allan Wind
A: 

How about traversing the PATH variable until you find the location of your script.

#!/bin/sh
IFS=:
for DIR in ${PATH}
do
   [ -f ${DIR}/`basename $0` ] && echo "found in ${DIR}" && break
done
IFS=
PaulB
A: 

This is linux specific, but you could use:

readlink /proc/$$/fd/255

Steve Baker
+20  A: 
SCRIPT_PATH="${BASH_SOURCE[0]}";
if([ -h "${SCRIPT_PATH}" ]) then
  while([ -h "${SCRIPT_PATH}" ]) do SCRIPT_PATH=`readlink "${SCRIPT_PATH}"`; done
fi
pushd . > /dev/null
cd `dirname ${SCRIPT_PATH}` > /dev/null
SCRIPT_PATH=`pwd`;
popd  > /dev/null

Works for all versions,including
when called via multple depth soft link,
when script called by command "source" aka . (dot) operator.
when arg $0 is modified from caller.
"./script" "/full/path/to/script" "/some/path/../../another/path/script" "./some/folder/script"
SCRIPT_PATH is given in full path, no matter how it is called.
Just make sure you locate this at start of the script.

This comment and code Copyleft, selectable license under the GPL2.0 or later or CC-SA 3.0 (CreativeCommons Share Alike) or later. (c) 2008. All rights reserved. No warranty of any kind. You have been warned.
http://www.gnu.org/licenses/gpl-2.0.txt
http://creativecommons.org/licenses/by-sa/3.0/
18eedfe1c99df68dc94d4a94712a71aaa8e1e9e36cacf421b9463dd2bbaa02906d0d6656

Thanks, I was hoping at least one answer would help with sourced scripts.
Joshua Swink
Nice! Could be made shorter replacing "pushd[...] popd /dev/null" by SCRIPT_PATH=`readlink -f $(dirname "${VIRTUAL_ENV}")`;
e-satis
This is by far the most "stable" version I've seen. Thank you!
Tomer Gabel
Should not the colon in the line 1 be moved in line two between the if- and then-statements?
ovanes
ovanes
A: 

This works in bash-3.2:

path="$( dirname "$( which "$0" )" )"

Here's an example of its usage:

Say you have a ~/bin directory, which is in your $PATH. You have script A inside this directory. It source*s script *~/bin/lib/B. You know where the included script is relative to the original one (the subdirectory lib), but not where it is relative to the user's current directory.

This is solved by the following (inside A):

source "$( dirname "$( which "$0" )" )/lib/B"

It doesn't matter where the user is or how he calls the script, this will always work.

Matt Tardiff
+25  A: 
DIRECTORY=$(cd `dirname $0` && pwd)

Is a useful one-liner which will give you the full directory name of the script no matter where it is being called from

dogbane
This is much better than my solution. I've been using this in my code now.
SpoonMeiser
Even better: DIR=$(cd $(dirname "$0"); pwd) Will work with spaces and other weird characters
Aaron Digulla
Matt Tardiff
A: 

short answer:

`dirname $0`

or

$(dirname $0)
Fabien
A: 

I usually do:

LIBDIR=$(dirname "$(readlink -f "$(type -P $0 || echo $0)")")
source $LIBDIR/lib.sh
A: 

Hmm, if in the path basename & dirname are just not going to cut it and walking the path is hard (what if parent didn't export PATH!). However, the shell has to have an open handle to its script, and in bash the handle is #255.

SELF=readlink /proc/$$/fd/255

works for me.

EDITOR HELP! WHAT IS HTML ENTITY FOR BACKTICK?!

Joshua
A: 

I want to make sure that the script is running in its directory. So cd $(dirname $(which $0) )

After this, if you really want to know where the you are running then run the command below. DIR=$(/usr/bin/pwd)

A: 

This is the only way I've found to tell reliably:

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

BillTorpey
A: 
ME=`type -p $0`
MDIR="${ME%/*}"
WORK_DIR=$(cd $MDIR && pwd)
+6  A: 

The dirname command is the most basic, simply parsing the path up to the filename off of the $0 (script name) variable:

dirname $0

But, as matt b pointed out, the path returned is different depending on how the script is called. pwd doesn't do the job because that only tells you what the current directory is, not what directory the script resides in. Additionally, if a symbolic link to a script is executed, you're going to get a (probably relative) path to where the link resides, not the actual script.

Some others have mentioned the readlink command, but at it's simplest, you can use:

dirname $(readlink -f $0)

readlink will resolve the script path to an absolute path from the root of the filesystem. So, any paths containing single or double dots, tildes and/or symbolic links will be resolved to a full path.

Here's a script demonstrating each of these, whatdir.sh:

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename $0`"
echo "dirname: `dirname $0`"
echo "dirname/readlink: $(dirname $(readlink -f $0))"

Running this script in my home dir, using a relative path:

>>>$ ./whatdir.sh 
pwd: /Users/phatblat
$0: ./whatdir.sh
basename: whatdir.sh
dirname: .
dirname/readlink: /Users/phatblat

Again, but using the full path to the script:

>>>$ /Users/phatblat/whatdir.sh 
pwd: /Users/phatblat
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

Now changing directories:

>>>$ cd /tmp
>>>$ ~/whatdir.sh 
pwd: /tmp
$0: /Users/phatblat/whatdir.sh
basename: whatdir.sh
dirname: /Users/phatblat
dirname/readlink: /Users/phatblat

And finally using a symbolic link to execute the script:

>>>$ ln -s ~/whatdir.sh whatdirlink.sh
>>>$ ./whatdirlink.sh 
pwd: /tmp
$0: ./whatdirlink.sh
basename: whatdirlink.sh
dirname: .
dirname/readlink: /Users/phatblat
phatblat
+1  A: 
function getScriptAbsoluteDir { # fold>>
    # @description used to get the script path
    # @param $1 the script $0 parameter
    local script_invoke_path="$1"
    local cwd=`pwd`

    # absolute path ? if so, the first character is a /
    if test "x${script_invoke_path:0:1}" = 'x/'
    then
        RESULT=`dirname "$script_invoke_path"`
    else
        RESULT=`dirname "$cwd/$script_invoke_path"`
    fi
} # <<fold
Stefano Borini
sorry I'm a bit of a bash scrip noob, do I call this function by just typing `getScriptAbsoluteDir` or `local currdir='getScriptAbsoluteDir'`?
Jiaaro
+1  A: 

A slight revision to the solution e-satis and 3bcdnlklvc04a pointed out in their answer

pushd $(dirname $(readlink -f "$BASH_SOURCE")) > /dev/null
SCRIPT_DIR="$PWD"
popd > /dev/null

This should still work in all the cases they listed.

Fuwjax
This works perfectly to get the "real" dirname, rather than just the name of a symlink. Thank you!
pyrony
+4  A: 

I tried every one of these and none of them worked. One was very close but had a tiny bug that broke it badly; they forgot to wrap the path in quotation marks.

Also a lot of people assume you're running the script from a shell so forget when you open a new script it defaults to your home.

Try this directory on for size:

/var/No one/Thought/About Spaces Being/In a Directory/Name/And Here's your file.text

This gets it right regardless how or where you run it.

#!/bin/bash
echo "pwd: `pwd`"
echo "\$0: $0"
echo "basename: `basename "$0"`"
echo "dirname: `dirname "$0"`"

So to make it actually useful here's how to change to the directory of the running script:

cd "`dirname "$0"`"

Hope that helps

Mike Bethany
A: 

None of these worked for a bash script launched by Finder in OS X - I ended up using: SCRIPT_LOC="ps -p $$|sed /PID/d|sed s:.*/Network/:/Network/:|sed s:.*/Volumes/:/Volumes/:"

Not pretty, but it gets the job done. (looks like the backticks at the insides of the double quotes are not coming through - you will need them, though.

tigfox
A: 

SCRIPT_DIR=$(cd ${0%/*} && pwd -P )

Puneet Madaan
A: 

Use a combination of readlink to canonicalize the name (with a bonus of following it back to its source if it is a symlink) and dirname to extract the directory name:

script="`readlink -f "${BASH_SOURCE[0]}"`"
dir="`dirname "$script"`"
alanwj