代码之家  ›  专栏  ›  技术社区  ›  Jonathan Leffler

创建符号链接后,您可以更改它指向的内容吗?

  •  112
  • Jonathan Leffler  · 技术社区  · 15 年前

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

    POSIX标准没有。Solaris 10没有。MacOS X 10.5(Leopard)没有。(我可以肯定,无论是AIX还是HP-UX都没有。从这个名单上判断 Linux system calls ,Linux也没有这样的系统调用。)

    有什么作用吗?

    (我希望答案是“不”。)


    既然证明一个否定是困难的,让我们重新组织一下这个问题。

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

    7 回复  |  直到 7 年前
        1
  •  98
  •   Ben Amos    7 年前

    阿法克,不,你不能。你必须把它移走然后重新创建。 实际上,您可以覆盖一个symlink,从而更新它引用的路径名:

    $ 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 选项将使 ln 对执行系统调用 unlink() 之前 symlink() . 下面,输出 strace 在我的Linux盒子上证明它:

    $ 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
    

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

    编辑 :以下是从复制的 Arto Bendiken's answer 在unix.stackexchange.com上,大约2016年。

    这个 可以 确实是原子性的 rename(2) ,方法是先在临时名称下创建新的符号链接,然后一次性完全覆盖旧的符号链接。作为 man page 国家:

    如果 新路径 引用符号链接,链接将被覆盖。

    在壳里,你可以用 mv -T 如下:

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

    你可以 斯特雷斯 最后一个确保它确实在使用的命令 重命名(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-T 斯特雷斯 是特定于Linux的。

    关于FreeBSD,使用 mv -h 交替地。

    编者按: 这就是卡皮斯特拉诺多年来的做法,从2.15年开始。见 this pull request .

        2
  •  151
  •   Taai    12 年前

    是的,你可以!

    $ ln -sfn source_file_or_directory_name softlink_name
    
        3
  •  12
  •   mark4o    15 年前

    不需要显式地取消链接旧的符号链接。您可以这样做:

    ln -s newtarget temp
    mv temp mylink
    

    (或使用等效的symlink和rename调用)。这比显式取消链接要好,因为重命名是原子的,所以可以确保链接始终指向旧的或新的目标。但是,这不会重用原始inode。

    在某些文件系统上,如果symlink足够短,它的目标将存储在inode本身(而不是块列表中);这是在创建时确定的。

    关于实际所有人和集团不重要的主张, symlink(7) 在Linux上,有一种情况非常重要:

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

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

    在Linux上,任何操作都不使用符号链接的权限; 权限始终为0777(所有用户的读、写和执行权限) 类别),不能更改。

        4
  •  2
  •   Markus Bucher    10 年前

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

    如果将源和目标混合在一起,使用-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
    

    当然,这是有意的,但通常会出错。因此,删除和重建symlink要做得更多,但也要节省一些:

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

    它至少保存了我的文件。

        5
  •  1
  •   matt b    15 年前

    不管怎样,取消链接并创建新的链接最终不会做同样的事情吗?

        6
  •  0
  •   Pierre    10 年前

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

    Fichier / Éditer le lien symbolique
    

    可译为:

    File / Edit symbolic link
    

    快捷方式是C-X C-S

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

    现在,我正试图找到一种同时编辑大量符号链接的方法(我就是这样来到这里的)。

        7
  •  0
  •   blizzrdof77 Guss    7 年前

    从技术上讲,没有内置命令来编辑现有的符号链接。它可以很容易地通过几个简短的命令来实现。

    这里有一点 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"
    }