readlink 是最直接轻量的获取软链接原始路径方式,不依赖外部工具且广泛支持;不带参数时原样返回链接内容,-f 选项可递归解析并补全为绝对路径但要求所有中间路径存在,-m 可替代 -f 用于不存在路径场景。

readlink 是最直接、最轻量的方式获取软链接原始路径,不需要额外依赖,几乎所有 Linux 发行版都自带。
直接读取软链接目标路径(不递归)
当软链接只有一层、且目标路径是相对路径时,用不带参数的 readlink 即可:
-
readlink mylink输出类似../bin/app或/usr/local/bin/python3—— 它原样返回链接文件里存的字符串,不做任何路径补全或解析 - 如果
mylink不是软链接(比如普通文件或目录),readlink默认静默退出,不输出任何内容,也不报错 - 这个行为容易让人误以为“命令没生效”,其实只是它严格遵循 POSIX:只对符号链接返回内容,其他类型一律无输出
获取最终绝对路径(-f 选项)
readlink -f 是脚本中最常用的组合,它会逐层展开所有中间软链接,并补全为绝对路径:
-
readlink -f /usr/bin/python可能输出/usr/bin/python3.11,即使中间经过/usr/bin/python → python3 → python3.11多层跳转 - 但注意:
-f要求路径中**所有中间组件必须真实存在**。比如readlink -f /nonexistent/link会失败并返回空,哪怕link本身是合法软链接 - 旧系统(如 CentOS 6 或某些嵌入式 BusyBox)可能不支持
-f,此时可用readlink -m替代 —— 它不要求中间路径存在,只做字符串解析和路径规范化
在 Shell 脚本中安全获取自身真实路径
写可被软链接调用的脚本时,$0 指向的是调用路径,不是脚本实际位置,必须用 readlink -f "$0" 修正:
-
SCRIPT_DIR=$(dirname "$(readlink -f "$0")")是标准写法,能正确处理./script.sh、/usr/local/bin/script(软链接)、甚至跨挂载点的情况 - 别漏掉
"$0"的双引号,否则含空格路径会出错;也别省略$(...)外层的命令替换,否则readlink输出会被 shell 当作命令执行 - 如果脚本可能被硬链接调用(少见),
readlink会失败(硬链接不是符号链接),这时需 fallback 到realpath "$0"或结合ls -i判断
避免缓冲区截断和空字符问题(C 程序调用 readlink())
系统调用 readlink() 和命令行工具不同,它**不会自动在结果末尾加 \0**,且返回值等于 bufsiz 时大概率被截断:
- 常见错误写法:
char buf[256]; readlink(path, buf, sizeof(buf)); printf("%s", buf);—— 若实际路径长于 255 字节,buf未以\0结尾,printf会越界读内存 - 正确做法:先用
lstat()获取st_size(符号链接内容长度),再分配刚好够的 buffer;或用循环 +readlink()自动扩容 - 更简单方案:用
readlink()返回值控制输出,例如write(STDOUT_FILENO, buf, len);,绕过字符串终止符问题
真正容易被忽略的不是怎么用 -f,而是它对路径存在性的隐含要求 —— 很多调试失败,是因为中间某一级目录已被删除,但软链接本身还存在,readlink -f 就会静默失败。这时候得换 readlink -m 或手动分段 readlink + dirname 检查。











