在 Linux 系统中,直接调用 realpath 即可获取绝对路径,无需手动检测当前目录或拼接 $PWD 变量。不过有一个关键点容易被忽视:默认情况下,若目标路径不存在,realpath 会直接抛出错误,这类细节在实际脚本编写时最容易导致异常。
realpath默认会解析符号链接,同时要求路径必须存在;若想保留链接本身,请使用-s选项;当路径可能尚未存在时,加上-m即可避免报错;批量处理多个路径时,一次性传入多个参数比循环更稳定可靠;在脚本中获取自身所在目录,推荐采用realpath "$0"的方式。
realpath 解析符号链接时默认追踪,不加选项即返回真实目标路径
举例来说,/usr/bin/python 通常是一个软链接,实际指向 /usr/bin/python3.10。执行以下命令:
realpath /usr/bin/python
输出结果为 /usr/bin/python3.10,而非链接本身。这一行为与 readlink -f 完全一致。
- 若想保留链接路径、不进行解析?加上
-s或--no-symlinks即可。 - 如果只想解析部分层级(例如父目录包含
..,但链接本身不需要追踪)?使用-L选项,不过实际应用中极少用到。 - 脚本中如果依赖“链接即路径”的逻辑,遗漏
-s可能导致后续的cp或test -e判定出错,这是常见的陷阱。
路径不存在时 realpath 默认报错,需用 -m 或 --canonicalize-missing
尝试执行 realpath nonexistent/file.txt,你会看到类似 realpath: nonexistent/file.txt: No such file or directory 的错误信息,并返回非零退出码——这对脚本中的条件判断来说是个硬伤。
- 若希望它安静地返回规范化路径(例如
/home/user/nonexistent/file.txt),必须加上-m。 -e(默认隐含)要求所有中间目录都存在;-m则放宽限制,只做字符串层面的规范化处理。- 如果路径中包含
../且上层目录不存在,-m仍然能计算出逻辑路径,但之后用test -d等命令操作时仍会失败——这一点需要提前预判。
批量处理多个路径时,realpath 单次调用比循环更可靠
传入多个参数,realpath 会按顺序逐个输出,每行一个:
realpath ./a ../b/c /tmp/link
相比编写 for p in ./a ../b/c /tmp/link; do realpath "$p"; done 更简洁,也能避免子 shell 环境变量污染或引号处理带来的麻烦。
- 路径中包含空格?加上
-z让输出以\0分隔,配合xargs -0可以安全地消费。 - 想让结果相对于某个目录(例如部署时统一转换为相对路径)?使用
--relative-to=/opt/app即可。 - 切勿直接使用
realpath *展开通配符——如果当前目录没有匹配项,shell 会原样将*传给realpath,导致报错。
Shell 脚本中获取自身所在目录,realpath "$0" 是最稳健的写法
许多人习惯使用 cd "$(dirname "$0")"; pwd,但这种方式会改变当前工作目录,并且在涉及符号链接时容易失效。
- 正确的做法:
SCRIPT_DIR=$(dirname "$(realpath "$0")")。 - 如果脚本可能通过符号链接调用,而你希望定位符号链接所在的目录(而非目标位置),则使用
dirname "$(realpath -s "$0")"。 realpath在绝大多数 Linux 发行版中属于coreutils,无需额外安装;但像 Alpine 这类精简系统需要先执行apk add coreutils。
真正容易被忽略的是:realpath 对路径中每个组件的存在性默认敏感,而脚本往往需要处理“即将被创建”的路径。不加 -m 的调用,在 CI/CD 或容器初始化阶段极易静默失败,这点值得格外留意。
