如何将当前工作目录设置为脚本目录?


569

我正在写一个bash脚本。我需要当前的工作目录始终是脚本所在的目录。

默认行为是脚本中的当前工作目录是运行它的外壳程序的目录,但是我不希望出现这种情况。


您是否考虑过将包装器脚本放在/ usr / bin之类的地方,以cd放入(硬编码)正确的目录中,然后执行您的脚本?
Dagg Nabbit

2
为什么需要脚本目录?解决潜在的问题可能是更好的方法。
bstpierre

12
我只想指出,您所说的“明显不受欢迎”的行为实际上是完全必要的-如果运行,myscript path/to/file我希望脚本评估相对于我当前目录的path / to / file,而不是脚本发生的任何目录。此外,ssh remotehost bash < ./myscript如BASH FAQ所述,使用该脚本运行脚本会发生什么?
戈登·戴维森


3
cd "${BASH_SOURCE%/*}" || exit
caw

Answers:


655
#!/bin/bash
cd "$(dirname "$0")"

7
dirname返回“。” 在Windows下使用bash时。因此,保罗的答案更好。
Tvaroh

7
同时返回“。” 在Mac OSX中
Ben Clayton 2013年

4
值得注意的是,如果符号链接构成的一部分,则事情可能会中断$0。例如,在您的脚本中,您可能希望../../引用该脚本位置上方两级的目录,但是如果正在使用符号链接,则不一定是这种情况。
Brian Gordon

20
如果您将脚本称为./script.则是正确的目录,并且更改为该脚本.也将最终script位于所位于的目录中,即当前的工作目录中。
2014年

6
如果从当前目录运行脚本,像这样bash script.sh,那么价值$0script.sh。该cd命令对您“起作用” 的唯一方法是,因为您不关心失败的命令。如果要使用set -o errexit(aka:)set -e来确保脚本不会遗漏失败的命令,那么这将不起作用,因为这cd script.sh是一个错误。可靠的[特定于重击]的方式是cd "$(dirname ${BASH_SOURCE[0]})"
Bruno Bronosky 2016年

322

以下内容也适用:

cd "${0%/*}"

语法中充分地阐述这个 StackOverflow的答案。



25
如果路径包含空格,请不要忘记用引号引起来。即cd“ $ {0%/ *}”
H.Rabiee

17
如果使用调用脚本,此操作将失败bash script.sh- $0只是文件名
Chris Watts

17
我会说这个答案太简洁了。您几乎不了解语法。关于如何阅读此内容的一些描述将很有帮助。
fraxture '16

2
这个技巧也不会产生子外壳,因此对于速度怪胎很有用。
teknopaul

184

尝试以下简单的一线:


对于所有UNIX / OSX / Linux

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

重击

dir=$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)

注意:命令中使用双破折号(-)表示命令选项的结尾,因此包含破折号或其他特殊字符的文件不会破坏命令。

注意:在Bash中,请使用${BASH_SOURCE[0]},以代替,$0否则在采购时路径可能会中断(source/.)。


对于Linux,Mac和其他* BSD:

cd "$(dirname "$(realpath "$0")")";

注意: realpath默认情况下,应将其安装在最受欢迎的Linux发行版中(例如Ubuntu),但是某些情况下可能会丢失,因此必须进行安装。

注意:如果您使用的是Bash,请使用${BASH_SOURCE[0]}代替$0,否则在采购时路径可能会中断(source / .)。

否则,您可以尝试类似的方法(它将使用第一个现有工具):

cd "$(dirname "$(readlink -f "$0" || realpath "$0")")"

对于Linux特定的:

cd "$(dirname "$(readlink -f "$0")")"

在* BSD / Mac上使用GNU readlink:

cd "$(dirname "$(greadlink -f "$0")")"

注意:您需要先coreutils安装(例如1.安装Homebrew,2。brew install coreutils)。


重击

在bash中,您可以使用Parameter Expansions来实现,例如:

cd "${0%/*}"

但是如果脚本是从同一目录运行的,则无法使用。

另外,您可以在bash中定义以下函数:

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

此函数有1个参数。如果参数已经具有绝对路径,则按原样打印,否则打印$PWD变量+文件名参数(不带./前缀)。

或以下是从Debian .bashrc文件中获取的版本:

function realpath()
{
    f=$@
    if [ -d "$f" ]; then
        base=""
        dir="$f"
    else
        base="/$(basename "$f")"
        dir=$(dirname "$f")
    fi
    dir=$(cd "$dir" && /bin/pwd)
    echo "$dir$base"
}

有关:

也可以看看:

如何在Mac上获得GNU的readlink -f的行为?


4
比流行的答案好得多,因为它可以解析系统链接,并说明不同的操作系统。谢谢!
丹尼斯

感谢您的回答。顶级的在我的Mac上工作过...但是-开关在cp@kenorb命令中做什么?
TobyG 2014年

3
--命令中使用双破折号()表示命令选项的结尾,因此包含破折号或其他特殊字符的文件不会破坏命令。尝试例如,通过创建文件touch "-test"touch -- -test,然后通过删除文件rm "-test"rm -- -test,看看其中的差别。
kenorb 2014年

1
如果可以的话,我会删除我的投票
lsh

1
@lsh它说只realpath弃用了Debian 软件包,而不是GNU realpath。如果您不清楚,可以提出修改建议。
kenorb 2015年

73
cd "$(dirname "${BASH_SOURCE[0]}")"

这简单。有用。


1
这应该是公认的答案。适用于OSX和Linux Ubuntu。
David Rissato Cruz

5
当脚本B源自其他脚本A且您需要使用相对于脚本B的路径时,这非常有用。谢谢。
恩里科

5
对于那些不幸不得不触摸Windows的我们来说,这在Cygwin中也适用。
布鲁诺·布鲁诺斯基

3
cd "${BASH_SOURCE%/*}" || exit
听到

在macOS Mojave上工作
Juan Boero

6

对于没有在其他地方进行符号链接(例如)的脚本,可接受的答案很好用$PATH

#!/bin/bash
cd "$(dirname "$0")"

但是,如果脚本是通过符号链接运行的,

ln -sv ~/project/script.sh ~/bin/; 
~/bin/script.sh

这将进入~/bin/目录而不是~/project/目录,这可能会破坏脚本,如果cd是包括相对于Windows的依赖关系~/project/

symlink安全答案如下:

#!/bin/bash
cd "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"

readlink -f 需要解析潜在的符号链接文件的绝对路径。

需要使用引号来支持可能包含空格的文件路径(不好的做法,但不能肯定不会出现这种情况)


4

该脚本似乎对我有用:

#!/bin/bash
mypath=`realpath $0`
cd `dirname $mypath`
pwd

无论我从哪里运行,pwd命令行都将脚本的位置作为当前工作目录回显。


3
realpath不太可能在任何地方安装。这可能并不重要,具体取决于OP的情况。
bstpierre

我的系统没有,realpath但是确实有readlink类似的东西。
暂停,直到另行通知。

2
默认情况下哪个dist没有安装realpath?Ubuntu拥有它。
kenorb


1
cd "`dirname $(readlink -f ${0})`"

你能解释一下你的答案吗?
祖鲁语2015年

1
尽管此代码可能有助于解决问题,但并未解释为什么和/或如何回答问题。提供这种额外的环境将大大提高其长期教育价值。请编辑您的答案以添加解释,包括适用的限制和假设。
Toby Speight


-6

如果您只需要打印当前的工作目录,则可以按照此步骤进行。

$ vim test

#!/bin/bash
pwd
:wq to save the test file.

授予执行权限:

chmod u+x test

然后执行脚本,./test您将看到当前的工作目录。


2
问题是如何确保脚本在其自己的目录中运行,包括该目录是否不在工作目录中。因此,这不是答案。无论如何,为什么这样做而不是仅仅...运行pwd?在我看来,很多浪费的按键。
underscore_d
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.