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

jam*_*her 500 bash scripting path

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

默认行为是脚本中的当前工作目录是我运行它的shell的目录,但我不想要这种行为.

ndi*_*dim 584

#!/bin/bash
cd "$(dirname "$0")"
Run Code Online (Sandbox Code Playgroud)

  • 如果你将脚本称为`./ script`,`.`是正确的目录,并且改为`.`它也将最终出现在`script`所在的目录中,即在当前的工作目录中. (19认同)
  • dirname返回'.' 在Windows下使用bash时.所以,保罗的答案更好. (6认同)
  • 也返回'.' 在Mac OSX中 (6认同)
  • 如果你从当前目录运行脚本,就像`bash script.sh`那样,`$ 0`的值是`script.sh`.`cd`命令为你"工作"的唯一方法是因为你不关心失败的命令.如果你使用`set -o errexit`(又名:`set -e`)来确保你的脚本不会超过失败的命令,那就不行了,因为`cd script.sh`是一个错误.可靠的[bash特定]方式是`cd"$(dirname $ {BASH_SOURCE [0]})"` (4认同)
  • 值得注意的是,如果符号链接构成"$ 0"的一部分,事情就会破裂.在您的脚本中,您可能希望,例如,`../../`引用脚本位置上方两级的目录,但如果符号链接在播放中则不一定如此. (3认同)
  • @BrunoBronosky:`dirname script.sh`打印`.`并以退出代码0退出。因此,执行了cd .`,并且退出代码为0。我不知道出现失败命令的位置。 (2认同)
  • @lyuboslav 引号很好。它们不会作为要由该子 shell 解析的字符串传递到某个子 shell。外壳使用这些内部引号来运行带有单个参数的“dirname”命令,而不以任何方式解释“$0”的值。然后,外部引号确保“dirname”的输出用作“cd”的单个参数,而不以任何方式解释该字符串。 (2认同)

小智 306

以下也有效:

cd "${0%/*}"
Run Code Online (Sandbox Code Playgroud)

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

  • 如果路径包含空格,请不要忘记用引号括起来.即cd"$ {0%/*}" (25认同)
  • 解释它是如何工作的:http://stackoverflow.com/questions/6393551/what-is-the-meaning-of-0-in-a-bash-script (16认同)
  • 我会说这个答案太简洁了.你几乎不了解语法.关于如何阅读这个的一些描述将是有帮助的. (16认同)
  • 如果使用`bash script.sh`调用脚本,则会失败 - "$ 0"将只是文件的名称 (15认同)
  • 如果脚本位于根目录中,则两者都不起作用,因为“${0%/*}”会扩展为空字符串 (2认同)
  • 这个技巧也不会产生一个子壳,所以对速度怪来说也是好事. (2认同)

ken*_*orb 171

尝试以下简单的单行:


适用于所有UNIX/OSX/Linux

dir=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
Run Code Online (Sandbox Code Playgroud)

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


对于Linux,Mac和其他*BSD:

dir=$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)
Run Code Online (Sandbox Code Playgroud)

白色空间支持:

cd "$(dirname "$(realpath "$0")")";
Run Code Online (Sandbox Code Playgroud)

注意:${BASH_SOURCE[0]}默认情况下应该安装在最流行的Linux发行版中(比如Ubuntu),但在某些情况下它可能会丢失,所以你必须安装它.

否则你可以尝试类似的东西(它将使用第一个现有的工具):

cd "$(dirname "$(readlink -f "$0" || realpath "$0")")"
Run Code Online (Sandbox Code Playgroud)

对于Linux特定:

cd "$(dirname "$(readlink -f "$0")")"
Run Code Online (Sandbox Code Playgroud)

在*BSD/Mac上使用GNU readlink:

cd "$(dirname "$(greadlink -f "$0")")"
Run Code Online (Sandbox Code Playgroud)

注意:您需要$0安装(例如1.安装Homebrew,2.source).


在bash中

在bash中,您可以使用参数扩展来实现这一点,例如:

cd "${0%/*}"
Run Code Online (Sandbox Code Playgroud)

但如果脚本从同一目录运行,则它不起作用.

或者,您可以在bash中定义以下函数:

realpath () {
  [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"
}
Run Code Online (Sandbox Code Playgroud)

此函数需要1个参数.如果参数已经是绝对路径,则按原样打印,否则打印.变量+文件名参数(不带realpath前缀).

或者这是从Debian ${BASH_SOURCE[0]}文件中获取的版本:

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"
}
Run Code Online (Sandbox Code Playgroud)

有关:

也可以看看:

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

  • 比流行的答案要好得多,因为它可以解析syslinks,并且可以解决不同的操作系统问题.谢谢! (4认同)
  • 命令中使用双短划线(` - `)来表示命令选项的结束,因此包含短划线或其他特殊字符的文件不会破坏命令.尝试例如通过`touch"-test"`和`touch - -test`创建文件,然后通过`rm"-test"`和`rm - -test`删除文件,看看差异. (3认同)
  • @lsh 它说只有 Debian `realpath` 软件包被弃用,而不是 GNU `realpath`。如果您认为不清楚,可以提出修改建议。 (2认同)
  • 难道所有像 `cd "$(dirname "$(realpath "$0")")"` 这样的例子都不应该在参数前使用 `--` ,比如 `cd "$(dirname -- "$(realpath --) “$0”)“)”`? (2认同)

Dan*_*ing 66

cd "$(dirname "${BASH_SOURCE[0]}")"
Run Code Online (Sandbox Code Playgroud)

这很简单.有用.

  • 当脚本B来自其他脚本A并且您需要使用相对于脚本B的路径时,这非常有用.谢谢. (5认同)
  • 这也适用于**Cygwin**,对于我们这些不幸不得不触摸Windows的人来说. (5认同)
  • 或`cd“ $ {BASH_SOURCE%/ *}” || 退出 (2认同)
  • 适用于 macOS Mojave (2认同)

And*_*ken 16

这里有很多正确的答案,但对我来说更有用的一个(确保脚本的相对路径保持可预测/工作)是使用 Pushd/popd:

pushd "$(dirname ${BASH_SOURCE:0})"
trap popd EXIT

# ./xyz, etc...
Run Code Online (Sandbox Code Playgroud)

这会将源文件的目录推送到导航堆栈,从而更改工作目录,但是,当脚本退出(无论出于何种原因,包括失败)时,将trap运行popd,在执行之前恢复当前工作目录。如果脚本执行后cd失败,则执行结束后您的终端可能会处于不可预测的状态 - 陷阱可以防止这种情况发生。


Jam*_*gan 6

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

#!/bin/bash
cd "$(dirname "$0")"
Run Code Online (Sandbox Code Playgroud)

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

ln -sv ~/project/script.sh ~/bin/; 
~/bin/script.sh
Run Code Online (Sandbox Code Playgroud)

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

symlink安全答案如下:

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

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

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


Ama*_*9MF 5

这个脚本似乎对我有用:

#!/bin/bash
mypath=`realpath $0`
cd `dirname $mypath`
pwd
Run Code Online (Sandbox Code Playgroud)

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

  • `realpath` 不太可能安装在任何地方。这可能无关紧要,具体取决于 OP 的情况。 (3认同)
  • 哪个dist默认没有安装realpath?Ubuntu 有。 (2认同)