readlink 是一个在 Linux 和 Unix-like 系统中非常实用的命令行工具,它的核心功能是“解析符号链接”,它会告诉你一个符号链接(软链接)真正指向的文件或目录的完整路径。

什么是符号链接?
在理解 readlink 之前,必须先明白什么是符号链接。
- 硬链接:指向文件 inode 的另一个名称,它和原始文件是同一个文件,只是有不同的名字,你不能为目录创建硬链接,也不能跨文件系统创建硬链接。
- 符号链接:也称为“软链接”,它就像一个快捷方式或一个指针,包含一个指向另一个文件或目录的路径字符串,符号链接可以指向不存在的文件(断开的链接),也可以跨文件系统创建。
示例:
# 创建一个普通文件 $ echo "hello world" > my_file.txt # 创建一个指向 my_file.txt 的符号链接 $ ln -s my_file.txt my_link # my_link 就是一个符号链接
readlink 命令的基本用法
readlink 命令最基本的功能就是显示符号链接指向的目标。
基本语法
readlink [选项] <符号链接文件>
示例
# 创建一个符号链接 $ ln -s /var/log/syslog my_syslog_link # 使用 readlink 查看它指向哪里 $ readlink my_syslog_link /var/log/syslog
常用选项
readlink 的强大之处在于它的选项,可以处理更复杂的情况。

-f 或 --canonicalize
这是 最常用、也最强大 的一个选项,它会递归地解析所有符号链接,并返回最终的、规范化的绝对路径。
- 规范化:意味着它会解析路径中的 (当前目录)、 (上级目录) 以及多余的 。
- 递归解析:如果目标本身也是一个符号链接,
-f会继续追踪下去,直到找到一个非链接的文件为止。
示例场景: 假设我们有以下文件结构和链接:
$ mkdir -p /home/user/project/src $ touch /home/user/project/src/main.c $ ln -s /home/user/project/src /home/user/project/code_link
我们想找到 code_link 下的 main.c 的绝对路径。
# 1. 不使用 -f,只能看到第一层指向 $ readlink code_link /home/user/project/src # 2. 使用 -f,可以得到最终的、规范的绝对路径 $ readlink -f code_link/main.c /home/user/project/src/main.c
这个 -f 选项在编写脚本时极其有用,因为它总能给你一个确定无误的、完整的路径。

-e 或 --canonicalize-existing
与 -f 类似,但它会确保路径最终指向一个真实存在的文件,如果路径断开(即链接指向一个不存在的文件),它会返回错误。
# 创建一个断开的链接 $ ln -s /nonexistent/file broken_link # -f 会返回它“应该”指向的路径,即使文件不存在 $ readlink -f broken_link /nonexistent/file # -e 会失败,因为文件不存在 $ readlink -e broken_link readlink: broken_link: No such file or directory
-m 或 --canonicalize-missing
与 -f 类似,但它允许路径中的任意部分不存在,它会将路径中存在的部分规范化,然后拼接上不存在的部分。
# 假设 /path/to 不存在,但 /path 存在 $ mkdir /path $ ln -s /path/to/my_link my_link # -f 会失败,因为 /path/to 不存在 $ readlink -f my_link /path/to/my_link # (如果系统允许,可能返回这个,但行为可能因实现而异) # -m 会成功,因为它不关心中间路径是否存在 $ readlink -m my_link /path/to/my_link
-n 或 --no-newline
默认情况下,readlink 的输出末尾会带一个换行符,此选项会去掉末尾的换行符,这在脚本中非常有用,当你想把 readlink 的结果赋值给一个变量时,可以避免变量末尾多出一个空行。
$ target=$(readlink -n my_link)
echo "The target is: '${target}'"
# 输出: The target is: '/var/log/syslog'
# (没有多余的空行)
-s 或 --silent
如果给定的文件不是符号链接,readlink 默认会报错并退出,使用 -s 选项可以静默处理,在这种情况下不输出任何内容并成功退出。
$ readlink not_a_link readlink: 'not_a_link': Not a symbolic link $ readlink -s not_a_link # (没有任何输出,命令成功执行)
-v 或 --verbose
显示详细的处理过程。
$ readlink -v code_link code_link -> /home/user/project/src
在 Shell 脚本中的应用
readlink 在脚本中主要用于获取一个可靠的、绝对的路径,这对于编写健壮的脚本至关重要。
场景: 你的脚本在 /home/user/project/bin 目录下,需要操作同一项目下的 config/app.conf 文件,你希望无论从哪里运行这个脚本,它都能正确找到配置文件。
#!/bin/bash
# 获取脚本所在的目录
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# 使用 readlink -f 获取配置文件的绝对路径
CONFIG_FILE=$(readlink -f "${SCRIPT_DIR}/../config/app.conf")
if [ -f "$CONFIG_FILE" ]; then
echo "Using configuration file at: $CONFIG_FILE"
# 在这里使用 $CONFIG_FILE...
else
echo "Error: Configuration file not found at $CONFIG_FILE" >&2
exit 1
fi
在这个例子中,readlink -f 确保了即使 config 目录或 app.conf 是一个符号链接,我们也能得到最终的、正确的路径。
相关命令:realpath
readlink -f 的功能与 realpath 命令几乎完全相同。realpath 是一个独立的命令,旨在提供 POSIX 标准化的路径解析功能。
在大多数现代 Linux 发行版(如 Ubuntu, Debian, CentOS 7+)中,realpath 是 coreutils 包的一部分,非常常见。
# readlink -f 和 realpath 的效果通常是一样的 $ readlink -f my_link /var/log/syslog $ realpath my_link /var/log/syslog
realpath 可用,使用它通常更具可读性,因为它明确表达了“获取真实路径”的意图,如果环境不确定,readlink -f 是一个更通用的选择,因为它在更多基础系统中是内置的 readlink 的一部分。
总结表格
| 选项 | 全称 | 描述 |
|---|---|---|
-f |
--canonicalize |
递归解析链接,返回规范的绝对路径。 |
-e |
--canonicalize-existing |
类似 -f,但要求最终路径必须存在,否则报错。 |
-m |
--canonicalize-missing |
类似 -f,但允许路径中的任意部分不存在。 |
-n |
--no-newline |
输出不包含末尾的换行符,适合用于脚本赋值。 |
-s |
--silent |
如果文件不是符号链接,不报错,静默退出。 |
-v |
--verbose |
显示链接指向的详细信息(如 link -> target)。 |
-z |
--zero |
用 NUL (\0) 字符分隔输出,而不是换行符,便于 xargs -0 处理。 |
核心要点:
readlink是查看符号链接指向谁的基本命令。readlink -f是获取绝对路径的“利器”,在脚本中极为常用。- 它与
realpath命令功能高度重合,realpath有时更具可读性。
