Getting the source directory of a Bash script from

2018-12-30 23:48发布

How do I get the path of the directory in which a Bash script is located, inside that script?

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

$ ./application

30条回答
浮光初槿花落
2楼-- · 2018-12-31 00:06

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 its 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
查看更多
有味是清欢
3楼-- · 2018-12-31 00:06

This gets the current working directory on Mac OS X 10.6.6:

DIR=$(cd "$(dirname "$0")"; pwd)
查看更多
初与友歌
4楼-- · 2018-12-31 00:06

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.

查看更多
十年一品温如言
5楼-- · 2018-12-31 00:06

Try the following cross-compatible solution:

CWD="$(cd -P -- "$(dirname -- "$0")" && pwd -P)"

as realpath or readlink commands are not always available (depending on the operating system) and ${BASH_SOURCE[0]} is available only in bash shell.

Alternatively you can try the following function in bash:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}

This function takes 1 argument. If argument has already absolute path, print it as it is, otherwise print $PWD variable + filename argument (without ./ prefix).

Related:

查看更多
公子世无双
6楼-- · 2018-12-31 00:07

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 sources 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.

查看更多
孤独总比滥情好
7楼-- · 2018-12-31 00:08

Try using:

real=$(realpath $(dirname $0))
查看更多
登录 后发表回答