128

是否有任何操作系统提供一种机制(系统调用——不是命令行程序)来更改符号链接(符号链接)引用的路径名——而不是通过取消链接旧链接并创建新链接?

POSIX 标准没有。Solaris 10 没有。MacOS X 10.5 (Leopard) 没有。(我可以肯定 AIX 和 HP-UX 都没有。从这个Linux 系统调用列表来看,Linux 也没有这样的系统调用。)

有什么可以做的吗?

(我期待答案是“否”。)


由于证明否定是困难的,让我们重新组织这个问题。

如果您知道某些(类 Unix)尚未列出的操作系统没有系统调用来重写符号链接的值(由 返回的字符串readlink())而不删除旧符号链接并创建新符号链接,请添加它 - 或者他们 -在一个答案中。

4

8 回答 8

167

是的你可以!

$ ln -sfn source_file_or_directory_name softlink_name
于 2012-07-02T16:46:08.123 回答
112

AFAIK,不,你不能。您必须删除它并重新创建它。实际上,您可以覆盖符号链接,从而更新它引用的路径名:

$ ln -s .bashrc test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 7 2009-09-23 17:12 test -> .bashrc
$ ln -s .profile test
ln: creating symbolic link `test': File exists
$ ln -s -f .profile test
$ ls -al test
lrwxrwxrwx 1 pascal pascal 8 2009-09-23 17:12 test -> .profile

编辑:正如 OP 在评论中指出的那样,使用该--force选项将对beforeln执行系统调用。下面,我的 linux 机器上的输出证明了这一点:unlink()symlink()strace

$ strace -o /tmp/output.txt ln -s -f .bash_aliases test
$ grep -C3 ^unlink /tmp/output.txt 
lstat64("test", {st_mode=S_IFLNK|0777, st_size=7, ...}) = 0
stat64(".bash_aliases", {st_mode=S_IFREG|0644, st_size=2043, ...}) = 0
symlink(".bash_aliases", "test")        = -1 EEXIST (File exists)
unlink("test")                          = 0
symlink(".bash_aliases", "test")        = 0
close(0)                                = 0
close(1)                                = 0

所以我想最后的答案是“不”。

编辑:以下内容是从大约 2016 年在 unix.stackexchange.com 上的 Arto Bendiken 的回答中复制的。

这确实可以用 原子完成rename(2)首先在一个临时名称下创建新的符号链接,然后一次干净地覆盖旧的符号链接。正如手册页所述:

如果newpath引用符号链接,则该链接将被覆盖。

在 shell 中,您可以执行mv -T以下操作:

$ mkdir a b
$ ln -s a z
$ ln -s b z.new
$ mv -T z.new z

您可以strace使用最后一个命令来确保它确实rename(2)在后台使用:

$ strace mv -T z.new z
lstat64("z.new", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
lstat64("z", {st_mode=S_IFLNK|0777, st_size=1, ...}) = 0
rename("z.new", "z")                    = 0

请注意,在上面,mv -Tstrace都是特定于 Linux 的。

在 FreeBSD 上,mv -h交替使用。

编者注:这就是 Capistrano 多年来一直这样做的方式,从 ~2.15 开始。请参阅此拉取请求

于 2009-09-23T14:59:39.437 回答
14

不必显式取消链接旧符号链接。你可以这样做:

ln -s newtarget temp
mv temp mylink

(或使用等效的符号链接和重命名调用)。这比显式取消链接要好,因为重命名是原子的,因此您可以放心,链接将始终指向旧目标或新目标。但是,这不会重用原始 inode。

在某些文件系统上,符号链接的目标存储在 inode 本身(代替块列表)中,如果它足够短的话;这是在创建时确定的。

关于实际所有者和组无关紧要的断言, Linux 上的symlink(7)表示存在一种重要的情况:

可以使用 lchown(2) 更改现有符号链接的所有者和组。符号链接的所有权唯一重要的是当链接被删除或重命名在设置了粘性位的目录中时(参见 stat(2))。

可以使用 utimensat(2) 或 lutimes(3) 更改符号链接的最后访问和最后修改时间戳。

在 Linux 上,符号链接的权限不用于任何操作;权限始终为 0777(所有用户类别的读取、写入和执行),并且无法更改。

于 2009-09-24T16:35:31.740 回答
2

只是对上述正确答案的警告:

如果混淆源和目标,使用 -f / --force 方法可能会丢失文件:

mbucher@server2:~/test$ ls -la
total 11448
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:27 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
-rw-r--r--  1 mbucher www-data 7582480 May 25 15:27 otherdata.tar.gz
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ln -s -f thesymlink otherdata.tar.gz 
mbucher@server2:~/test$ 
mbucher@server2:~/test$ ls -la
total 4028
drwxr-xr-x  2 mbucher www-data    4096 May 25 15:28 .
drwxr-xr-x 18 mbucher www-data    4096 May 25 15:13 ..
-rw-r--r--  1 mbucher www-data 4109466 May 25 15:26 data.tar.gz
lrwxrwxrwx  1 mbucher www-data      10 May 25 15:28 otherdata.tar.gz -> thesymlink
lrwxrwxrwx  1 mbucher www-data      11 May 25 15:26 thesymlink -> data.tar.gz

当然这是有意的,但通常会发生错误。因此,删除和重建符号链接需要更多的工作,但也可以节省一点:

mbucher@server2:~/test$ rm thesymlink && ln -s thesymlink otherdata.tar.gz 
ln: creating symbolic link `otherdata.tar.gz': File exists

这至少保留了我的文件。

于 2014-05-25T13:32:47.457 回答
1

无论如何,取消链接并创建新链接最终不会做同样的事情吗?

于 2009-09-23T14:59:46.580 回答
0

以防万一:有一种方法可以使用午夜指挥官 (mc) 编辑符号链接。菜单命令是(在我的 mc 界面上用法语):

Fichier / Éditer le lien symbolique

可以翻译成:

File / Edit symbolic link

快捷方式是 Cx Cs

也许它在内部使用ln --force命令,我不知道。

现在,我正在尝试找到一种方法来一次编辑大量符号链接(这就是我到达这里的方式)。

于 2014-07-07T18:11:25.660 回答
0

从技术上讲,没有用于编辑现有符号链接的内置命令。只需几个简短的命令即可轻松实现。

这是我为更新现有符号链接而编写的一个小bash/zsh 函数:

# -----------------------------------------
# Edit an existing symbolic link
#
# @1 = Name of symbolic link to edit
# @2 = Full destination path to update existing symlink with 
# -----------------------------------------
function edit-symlink () {
    if [ -z "$1" ]; then
        echo "Name of symbolic link you would like to edit:"
        read LINK
    else
        LINK="$1"
    fi
    LINKTMP="$LINK-tmp"
    if [ -z "$2" ]; then
        echo "Full destination path to update existing symlink with:"
        read DEST
    else
        DEST="$2"
    fi
    ln -s $DEST $LINKTMP
    rm $LINK
    mv $LINKTMP $LINK
    printf "Updated $LINK to point to new destination -> $DEST"
}
于 2017-11-26T22:19:03.727 回答
0

您可以在 Linux 中通过以下两种方式之一修改一次创建的软链接

  1. 一种是您可以使用 rm 删除现有软链接,然后再次使用 ln -s 命令创建新的软链接。
  2. 但是,这可以一步完成,您可以使用“ln -vfns Source_path Destination_path”命令将现有软链接替换为更新的路径。

列出目录中的初始所有文件

$ ls -lrt 
drwxrwxr-x. 3 root    root      110 Feb 27 18:58 test_script
$

使用 ln -s 命令为 test_script 创建软链接测试。

$ ln -s test_script test
$ ls -lrt
drwxrwxr-x. 3 root    root      110 Feb 27 18:58 test_script
lrwxrwxrwx. 1 root    root       11 Feb 27 18:58 test -> test_script
$

使用单个命令使用新目录 test_script/softlink 更新软链接测试

$ ln -vfns test_script/softlink/ test
'test' -> 'test_script/softlink/'
$

列出新的软链接位置

$ ls -lrt
lrwxrwxrwx. 1 root    root       21 Feb 27 18:59 test -> test_script/softlink/
$

ln --帮助

-v, --verbose 打印每个链接文件的名称

-f, --force 删除现有的目标文件

-n, --no-dereference 如果 LINK_NAME 是符号,则将其视为普通文件

-s, --symbolic 建立符号链接而不是硬链接

于 2022-02-28T05:45:17.957 回答