Shell 脚本如何获取当前脚本所在目录绝对路径不受 cd 影响?

文章导读
在 Bash 脚本中获取不受 cd 影响的脚本所在目录绝对路径,最可靠的方法是使用 ${BASH_SOURCE[0]} 配合 dirname 和 pwd 命令。该方案适用于 Bash 环境,不适用于纯 POSIX sh 脚本,且需注意符号链接带来的路径差异。
📋 目录
  1. 命令速用版
  2. 为什么会这样
  3. 分步处理
  4. 怎么验证是否生效
  5. 常见坑
  6. 常见问题
  7. 参考来源
A A

在 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"。

Shell 脚本如何获取当前脚本所在目录绝对路径不受 cd 影响?

3. 检查权限和存在性:在使用前增加 test -d "$SCRIPT_DIR" 判断目录是否可读。

怎么验证是否生效

通过在不同目录运行脚本并输出路径变量来确认结果稳定性。

1. 在脚本末尾添加 echo "Script Dir: $SCRIPT_DIR"。

2. 进入任意其他目录,使用绝对路径运行脚本,观察输出是否为脚本所在目录。

3. 在脚本中间执行 cd /tmp 后,再次 echo "$SCRIPT_DIR",确认路径未发生变化。

常见坑

符号链接、空格路径和 Shell 兼容性是主要风险点。

Shell 脚本如何获取当前脚本所在目录绝对路径不受 cd 影响?

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