在 Bash 脚本中获取不受 cd 影响的脚本所在目录绝对路径,最可靠的方法是使用 ${BASH_SOURCE[0]} 配合 dirname 和 pwd 命令。该方案适用于 Bash 环境,不适用于纯 POSIX sh 脚本,且需注意符号链接带来的路径差异。
先说结论:使用 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 可稳定获取脚本所在目录。
- 适合 Bash 脚本环境,兼容大多数 Linux 发行版
- 先看脚本是否通过符号链接调用,确认是否需要物理路径
- 建议用 echo 输出变量验证路径是否符合预期
命令速用版
直接在脚本开头添加以下代码行,将结果存入变量供后续使用。
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"为什么会这样
$0 和 pwd 会随调用方式或目录切换变化,而 BASH_SOURCE 记录文件原始路径。
变量 $0 在脚本被 sourced 或不同方式调用时会指向 shell 名称或相对路径,pwd 则反映进程当前工作目录。${BASH_SOURCE[0]} 专门存储当前执行脚本的文件名,结合 dirname 提取目录部分,再通过 cd 和 pwd 转换为绝对路径,从而隔离了外部目录切换的影响。
分步处理
按照定义、引用、检查的顺序将路径逻辑植入脚本。
1. 在脚本顶部定义变量:使用上述命令速用版代码行。
2. 在需要路径处引用变量:使用 "$SCRIPT_DIR" 拼接文件路径,例如 "$SCRIPT_DIR/config.txt"。
3. 检查权限和存在性:在使用前增加 test -d "$SCRIPT_DIR" 判断目录是否可读。
怎么验证是否生效
通过在不同目录运行脚本并输出路径变量来确认结果稳定性。
1. 在脚本末尾添加 echo "Script Dir: $SCRIPT_DIR"。
2. 进入任意其他目录,使用绝对路径运行脚本,观察输出是否为脚本所在目录。
3. 在脚本中间执行 cd /tmp 后,再次 echo "$SCRIPT_DIR",确认路径未发生变化。
常见坑
符号链接、空格路径和 Shell 兼容性是主要风险点。
1. 符号链接:如果脚本通过 symlink 调用,${BASH_SOURCE[0]} 可能返回链接路径而非物理路径,需加 pwd -P 解析。
2. 空格路径:变量引用必须加双引号,否则路径含空格时会截断。
3. Shell 兼容性:${BASH_SOURCE[0]} 是 Bash 特性,在 /bin/sh 指向 dash 的系统上可能无效,需改用 $0 并处理相对路径。
常见问题
为什么不用 $0 获取脚本路径?
$0 在脚本被 source 或某些调用方式下会变成 shell 名称或相对路径,不如 BASH_SOURCE 稳定。
脚本被 source 执行时路径会变吗?
不会,${BASH_SOURCE[0]} 在脚本被 source 时依然指向被 source 的文件路径,而 $0 会指向当前 shell。
如何在 POSIX sh 中实现类似功能?
POSIX sh 没有 BASH_SOURCE,通常需用 $0 配合 readlink 或手动判断相对路径,可靠性较低。
参考来源
GNU Project, Bash Variables - GNU Bash Manual, https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html