当工具、配置文件或发布目录移动时,你并不总是想逐个修改指向它的脚本和快捷方式。符号链接可以给你一个稳定的名称,让它始终指向正确的目标,而 ln 命令正是 Linux 中创建这些链接的工具。

本指南介绍如何使用 ln 命令在 Linux 中创建符号链接,如何安全地覆盖或更新它们,以及如何清理失效链接。

如何使用 ln 命令

ln 是一个用于在文件之间创建链接的命令行工具。默认情况下,ln 命令创建硬链接。要创建符号链接,请使用 -s (--symbolic) 选项。

创建符号链接的 ln 命令语法如下:

ln -s [OPTIONS] FILE LINK
  • 如果同时指定了 FILE 和 LINK,ln 将从第一个参数 (FILE) 指定的文件创建到第二个参数 (LINK) 指定的文件的链接。
  • 如果只给出了一个文件作为参数,或者第二个参数是点 (.),则 ln 会在当前工作目录中创建到该文件的链接。符号链接将与它所指向的文件具有相同的名称。

默认情况下,成功时 ln 不产生任何输出并返回零。

创建指向文件的符号链接

要为给定文件创建符号链接,请打开终端并输入:

ln -s source_file symbolic_link

将 source_file 替换为您要链接的现有文件的名称,将 symbolic_link 替换为您希望链接具有的名称。在以下示例中,我们创建了一个名为 my_link.txt 的符号链接,它指向名为 my_file.txt 的文件:

ln -s my_file.txt my_link.txt

要验证符号链接是否成功创建,请使用 ls 命令:

ls -l my_link.txt

输出结果如下所示:

lrwxrwxrwx 1 ggdoc users 11 Nov  2 23:03 my_link.txt -> my_file.txt

l 字符是一个文件类型标志,表示符号链接。-> 符号显示符号链接指向的文件。

如果删除或移动目标文件,符号链接将会悬空(失效),应予以移除。

创建指向目录的符号链接

创建指向目录的符号链接的命令与创建指向文件的符号链接的命令相同。将目录名称指定为第一个参数,符号链接指定为第二个参数。

例如,如果要将 /mnt/my_drive/movies 目录创建符号链接到 ~/my_movies 目录,您可以运行:

ln -s /mnt/my_drive/movies ~/my_movies

相对符号链接与绝对符号链接

符号链接存储的是您输入的路径,而不是它在创建时解析到的路径。这一个细节解释了大多数失效链接的原因。要遵循以下示例,请创建一个示例文件和一个用于存放链接的目录:

touch my_file.txt
mkdir -p links

当您给 ln 一个相对路径时,链接会从链接所在的目录开始查找该路径,而不一定是您运行命令的目录:

ln -s my_file.txt links/broken_link.txt

新链接位于 links/ 中,因此它会在 links/ 内部查找 my_file.txt,而该目录中并不存在该名称的文件。列表输出显示了存储的路径,从而暴露了问题:

ls -l links/broken_link.txt
lrwxrwxrwx 1 ggdoc users 11 Jul 30 09:14 links/broken_link.txt -> my_file.txt

输出显示链接存储了 my_file.txt,它会在 links/ 目录内而非当前目录中解析。

绝对路径不依赖于包含链接的目录。以下命令使用 $PWD 创建指向示例文件的带有完整路径的链接:

ln -s "$PWD/my_file.txt" links/absolute_link.txt

当您使用 GNU Coreutils 时,ln 可以通过 -r (--relative) 选项为您计算出相对路径。它会获取您指定的目标,并将其重写为相对于链接位置的路径:

ln -sr my_file.txt links/relative_link.txt

使用 ls -l 验证存储的路径:

ls -l links/relative_link.txt
lrwxrwxrwx 1 ggdoc users 14 Jul 30 09:16 links/relative_link.txt -> ../my_file.txt

这次 ln 存储了 ../my_file.txt,它指回 links/ 之外的真正文件。-r 选项是 GNU 扩展功能,并非在每个 ln 实现中都可用。当它不可用时,请自行指定相对目标:

ln -s ../my_file.txt links/portable_link.txt

当您在保持布局不变的情况下移动整个目录树时,这两种形式都能正常工作,这适用于源代码检出、点文件以及任何您之后可能移动的内容。对于 /usr/local/bin 等不会移动的系统位置,请保存绝对路径。

链接类型

Linux 和 UNIX 系统有两种链接类型,ln 都可以创建:

  • 软链接。符号链接,也称为软链接,是一个保存另一个文件或目录路径的小文件。它类似于 Windows 中的快捷方式,可以跨分区和文件系统指向目标,也可以指向目录。
  • 硬链接。硬链接是现有文件的另一个名称。两个或多个名称共享相同的 inode,因此它们指向磁盘上的相同数据。一个文件可以有很多硬链接,但在大多数系统中它们仅适用于文件,并且不能跨文件系统。

到目前为止所涉及的内容都使用了符号链接,这是大多数任务所需要的。硬链接是 ln 功能的另一半。

创建硬链接

如果不使用 -s 标志,ln 将创建硬链接而非符号链接。硬链接指向与原始文件相同的 inode,因此两个名称指向磁盘上完全相同的数据。

要创建硬链接,请去掉 -s:

ln my_file.txt my_hardlink.txt

如果您使用 ls -li 列出文件,两个名称将共享相同的 inode 编号:

ls -li my_file.txt my_hardlink.txt
1234567 -rw-r--r-- 2 ggdoc users 12 Apr 29 10:00 my_file.txt
1234567 -rw-r--r-- 2 ggdoc users 12 Apr 29 10:00 my_hardlink.txt

链接计数列中的 2 表示有两个名称指向同一个 inode。硬链接不能跨文件系统,并且在大多数系统上不能指向目录。当您需要其中任何一种功能时,请使用符号链接。有关两种链接类型差异的完整说明,请参阅硬链接与符号链接。

覆盖和更新符号链接

如果您尝试创建已存在的符号链接,ln 命令将输出错误消息。

ln -s my_file.txt my_link.txt
ln: failed to create symbolic link 'my_link.txt': File exists
Warning-f 选项可能替换常规的目标文件,而不仅仅是符号链接。请先运行 ls -l my_link.txt 验证它是否是您打算替换的链接。

在验证目标之后,使用 -f (--force) 选项进行替换:

ln -sf my_file.txt my_link.txt

如果现有链接指向一个目录,仅使用 -f 将无法达到预期效果。ln 会跟随符号链接并在目标目录内创建新链接,而不是替换链接本身。要就地替换链接,请添加 -n (--no-dereference) 标志:

ln -sfn /opt/app/releases/2.1.0 /opt/app/current

这种模式在简单的部署脚本中很常见。/opt/app/current 是一个始终指向当前活动发布目录的符号链接,而 ln -sfn 会用指向新发布的链接替换它。

对于更严格的原子交换,可以创建一个临时符号链接并将其移动到现有链接上:

ln -s /opt/app/releases/2.1.0 /opt/app/current.tmp
mv -Tf /opt/app/current.tmp /opt/app/current

mv -T 将目标视为普通路径,而不是将临时链接移入目录。在同一个文件系统上,最终的重命名是原子操作。

列出和查找符号链接

要检查单个文件是否为符号链接,请使用 ls -l。符号链接以 l 作为第一个字符,并且有一个指向目标的箭头:

ls -l /usr/bin/python3
lrwxrwxrwx 1 root root 10 Mar 14 09:12 /usr/bin/python3 -> python3.12

要列出目录下的所有符号链接,请询问 find 查找文件类型 l:

find /etc -type l

要查找损坏的符号链接(目标已不存在的链接),请使用 find 搭配 -xtype l:

find /etc -xtype l

-xtype l 在解引用后评估类型,因此目标缺失的符号链接会被报告为链接,而不是普通文件或目录。

使用 readlink 解析目标

当符号链接指向另一个符号链接,或者您想知道它解析到的绝对路径时,ls -l 仅显示直接目标。readlink 命令会显示跳转一步的结果,而 readlink -f 会沿着整个链走到最终的规范路径。

readlink /usr/bin/python3
python3.12
readlink -f /usr/bin/python3
/usr/bin/python3.12

大多数脚本都需要 readlink -f 形式,因为它返回的路径可以安全地传给其他命令,无需担心需要经过多少间接步骤。

符号链接权限

您在符号链接上看到的模式(lrwxrwxrwx)具有误导性。它总是显示为 777,因为 Linux 忽略链接自身的权限,并使用目标的权限进行任何读取、写入或执行操作。对符号链接运行 chmod 会跟随链接并更改目标的模式,而不是链接本身的模式。

在 Linux 上,通常无法使用 GNU chmod 更改符号链接节点的权限。请改为更改目标文件的权限,并将 ls -l 显示的符号链接模式视为信息性内容。

删除符号链接

要删除符号链接,请使用 unlink 或 rm 命令。

unlink 的语法非常简单:

unlink symlink_to_remove

使用 rm 删除符号链接与删除文件相同:

rm symlink_to_remove

无论使用哪个命令,删除符号链接时都不要在名称末尾附加 / 尾斜杠。

快速参考

如需可打印的快速参考,请参阅 ln 速查表。

任务命令
创建符号链接ln -s source link_name
创建指向相对目标的符号链接(GNU ln)ln -sr source dir/link_name
创建硬链接ln source hardlink_name
替换已验证的符号链接ln -sfn source link_name
原子性地替换目录符号链接ln -sfn /new/target /path/current
列出目录中的符号链接find /path -type l
查找损坏的符号链接find /path -xtype l
解析符号链接的目标readlink -f link_name
删除符号链接unlink link_name 或 rm link_name

故障排除

创建链接时出现 File exists
目标路径已被占用。使用 ls -l 检查该路径。如果它是要替换的符号链接,请使用 ln -sfn new_target link_name。如果是普通文件或目录,请在确认删除或移动操作安全后再进行。

损坏或悬空符号链接
目标已被重命名、移动或删除。还可能是链接存储了相对路径,无法从链接所在的目录解析。运行 ls -l 查看存储的路径,然后使用 ln -sfn 将链接指向新位置,使用 GNU ln -sr 重建链接,或使用 unlink 删除它。

Too many levels of symbolic links
符号链接最终指向自身,形成循环。readlink -f 在无法解析链时会失败,并且不会显示中间的每一步。使用 readlink link_name 检查直接目标,对链中的每个符号链接重复此命令,并替换或删除形成循环的链接。

创建链接时权限被拒绝
您对链接路径的父目录没有写权限。请以足够权限运行命令,或将链接放在您拥有的目录中。

chmod 对符号链接无效
在 Linux 上,chmod 会跟随符号链接并修改目标。GNU chmod 不提供可移植的方法来更改符号链接节点的权限,而且 Linux 在正常访问检查中会忽略这些权限。

常见问题解答

ln -sf 和 ln -sfn 有什么区别?
ln -sf 会覆盖目标,但如果目标是目录的符号链接,ln 会跟随该符号链接并将新链接写入目标目录内。添加 -n 告诉 ln 不要解引用目标,这样链接本身会被替换。当目标可能已经是目录的符号链接时,请使用 ln -sfn。对于更新期间读取者可能点击链接的部署路径,请使用临时符号链接加上 mv -T 模式(如上所示)。

硬链接和符号链接有什么区别?
硬链接是同一 inode 的另一个名称,因此两个名称引用磁盘上的相同数据,并共享权限和所有权。符号链接是一个存储目标路径的小文件,可以跨文件系统,并且可以指向目录。如果符号链接的目标被删除,符号链接将变为损坏;删除一个硬链接后,数据仍可通过其他硬链接访问。

sudo ln 有什么不同吗?
sudo 仅更改运行命令的用户。链接本身的创建行为相同。当需要在您没有所有权的目录(例如 /usr/local/bin)中创建链接时,请使用 sudo ln。

如何找到目录中的所有符号链接?
运行 find /path -type l 列出它们,或运行 find /path -xtype l 仅列出损坏的符号链接。

符号链接可以指向尚不存在的文件吗?
可以。ln -s 在创建时不会检查目标是否存在。在目标创建之前,链接将被视为损坏,这在填充目录树之前布局目录结构时有时很有用。