我如何找到一个Bash脚本位于该脚本内部的目录的路径?

我想用Bash脚本作为另一个应用程序的启动器,我想将工作目录更改为Bash脚本所在的目录,所以我可以在该目录中的文件上运行,如下:

$ ./application

当前回答

我通常将以下列入我的脚本的顶部,这在大多数情况下工作:

[ "$(dirname $0)" = '.' ] && SOURCE_DIR=$(pwd) || SOURCE_DIR=$(dirname $0);
ls -l $0 | grep -q ^l && SOURCE_DIR=$(ls -l $0 | awk '{print $NF}');

第一行根据PWD的值指定源,如果从当前路径运行,或者如果从其他地方呼叫,则命名。

第二行检查路径,以确定它是否是一个同链接,如果是这样,更新 SOURCE_DIR 到链接本身的位置。

可能有更好的解决方案在那里,但这是我成功的最干净的。

其他回答

我已经比较了许多答案,并出现了一些更紧凑的解决方案. 这些似乎处理所有疯狂的边缘案例,从你最喜欢的组合:

绝对路径或相对路径 文件和目录 软链接 作为脚本, bash 脚本, bash -c 脚本, 源脚本, 或. 脚本 空间, 标签, 新闻, Unicode, 等 在目录和 / 或 文件名 Filenames 从一个 hyphen

如果您正在运行从Linux,似乎使用proc操作是找到目前运行脚本的完全解决源的最佳解决方案(在互动会议中,链接点到相应的 /dev/pts/X):

resolved="$(readlink /proc/$$/fd/255 && echo X)" && resolved="${resolved%$'\nX'}"

absolute_path=$(readlink -e -- "${BASH_SOURCE[0]}" && echo x) && absolute_path=${absolute_path%?x}
dir=$(dirname -- "$absolute_path" && echo x) && dir=${dir%?x}
file=$(basename -- "$absolute_path" && echo x) && file=${file%?x}

ls -l -- "$dir/$file"
printf '$absolute_path: "%s"\n' "$absolute_path"

选择的答案非常好,我把我的解决方案发送给任何人寻找更短的替代方案,这些解决方案仍然涉及来源、执行、完整路径、相对路径和同步链接,最后,这将在 macOS 上工作,因为不能假设GNU的核心路径的阅读链接版本可用。

GOTCHA是它不使用Bash,但它很容易在Bash脚本中使用,虽然OP没有在解决方案的语言上设置任何限制,但它可能是最好的,大多数人已经留在Bash世界中。

PHP 可在 macOS 默认情况下,并安装在其他平台上,但不一定是默认情况下. 我意识到这是一个缺点,但我会留下这个在这里,任何人来自搜索引擎,无论如何。

export SOURCE_DIRECTORY="$(php -r 'echo dirname(realpath($argv[1]));' -- "${BASH_SOURCE[0]}")"

使用“0”字母:

#!/usr/bin/env bash

echo "The script you are running has basename $( basename -- "$0"; ), dirname $( dirname -- "$0"; )";
echo "The present working directory is $( pwd; )";

使用 pwd 单独不会工作,如果您不从它包含的目录中运行脚本。

[matt@server1 ~]$ pwd
/home/matt
[matt@server1 ~]$ ./test2.sh
The script you are running has basename test2.sh, dirname .
The present working directory is /home/matt
[matt@server1 ~]$ cd /tmp
[matt@server1 tmp]$ ~/test2.sh
The script you are running has basename test2.sh, dirname /home/matt
The present working directory is /tmp

这是我唯一能以可靠的方式说的话:

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

下面是简单而正确的方式:

actual_path=$(readlink -f "${BASH_SOURCE[0]}")
script_dir=$(dirname "$actual_path")

解释:

${BASH_SOURCE[0]} - 完整的路径到脚本. 这个值将是正确的,即使脚本是源,例如源 <(echo 'echo $0') 打印 bash,同时取代它为 ${BASH_SOURCE[0]} 将打印整个路径的脚本。