如何编辑符号链接?


64

我对符号链接的基本理解是作为一个特殊文件,该文件包含另一个文件的字符串路径。内核的VFS可以将其中的很多内容抽象出来,但是是否有任何原因导致符号链接似乎无法编辑?

换句话说:我可以编辑符号链接吗?如果没有,为什么不呢?


我确实知道,有多种替换符号链接的方法(答案部分中当前有两个替代方法),但对为什么替换似乎是处理符号链接的唯一方法的解释将很有趣。您为什么不能只更改他们指向的位置?


您的理解有些局限;之所以将其称为“文件”,是因为没有比这更好的词了。
2013年

5
与Windows变体的令人尴尬的暴行不同,posix风格的符号链接在文件系统层本身上/之中运行。编辑一个文件的唯一方法是直接编辑文件系统-这通常是不值得的。
沙杜尔

@Shadur的.lnk文件是不是真的符号链接与开始(和NTFS 已经不得不因为Vista的正确的符号链接); 它们更像是执行命令的快捷方式,无论是更改到特定文件夹还是使用特定参数和特定CWD启动程序。
JAB 2016年

Answers:


36

鉴于-f只进行了无声替换,您可以使用mv -T(-T使它工作,即使/loc.../link是目录)可以进行原子替换

ln -s /location/to/link linkname
# ... 
ln -s /location/to/link2 newlink
mv -T newlink linkname

linkname 在整个过程中都可以访问。


7
尽管您仍在进行替换而不是编辑(新链接具有新的inode编号),但这确实可以实现原子替换。
psusi

2
@psusi我完全同意,在某些情况下,这只是比其他答案更好的技术选择。
奥利

如果要将链接重定向到另一个目标,则更改它的inode编号似乎是一个很小的更改。
AMS

4
假定linkname不是目录的符号链接。如果在GNU或FreeBSD 上使用if -T选项,可以避免这种情况。请注意,这样不会保留链接的权限(在重要的系统上)。mv-hln -sf
斯特凡Chazelas

更改目录符号链接的另一种解决方案是使用-n选项,例如:ln -sfn DESTINATION_DIRECTORY LINK_NAME。在askubuntu.com/a/186227/69004
sobi3ch

22

如果进行编辑,则意味着要更改它指向的文件,那么可以:

$ 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

-f参数(--force)传递给ln时,它将导致它在调用unlink()系统调用之前symlink()

取自以下堆栈溢出答案


9
我认为这是否可以视为“编辑”是有问题的,因为unlink(); symlink(); 不是原子的,因此在极短的时间内不存在该链接。
重播

@ mauro.stettler是的,您是对的。但是我想这取决于您的观点。如果仅考虑最终结果,则也许可以将其视为已编辑,而无需考虑其他因素。
NlightNFotis

1
Unix时间共享系统文章中引用部分描述了链接。这些与OP询问的符号链接(符号链接)完全不同。
2013年

4
请注意,它假定test的目标不是目录。否则,ln -s -f .profile test.profile在该目录中创建符号链接。GNU ln可以-T选择避免这种情况。
斯特凡Chazelas

9

符号链接需要进行原子修改。如果您在编写它们的过程中途做不到,那么它们将无法工作。符号链接的内容很小(Linux上最多4095个字符:文件路径的最大长度),因此在内核级别上编辑符号链接的一部分毫无意义。因此,内核不提供任何用于编辑符号链接的接口,仅提供用于创建新接口的接口,即symlink系统调用(以及unlink用于删除任何文件的通用接口)。

symlink系统调用只能创建一个新的符号链接,它不会删除任何现有的文件。这很烦人,但与其他创建文件的系统调用保持一致,例如open(可以创建新文件或截断现有文件,但不能用新创建的文件替换现有文件)和mkdir

在外壳中,您已经发现,虽然不能用ln命令原子地替换符号链接(ln -sf取消链接前一个文件然后创建符号链接),但是可以通过以下操作来实现:首先在临时名称下创建一个符号链接,然后然后将其移动到位。

tmp=$(TMPDIR=$(dirname -- "$link") mktemp)
ln -sf -- "$target" "$tmp"
mv -f "$tmp" "$link"

2
mv -f(如ln -sf)无法$link指向目录。GNU ln和mv -T为此。mv(重命名系统调用)将始终更改inode,$linkln -sfT(unlink + symlink)可能会重复使用相同的索引。
斯特凡Chazelas

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"
}

抱歉,但您的“答案”仅与所提出的问题相关。
user2233709 '17

@ user2233709,您好:用户的问题“ 我如何编辑符号链接? ”已在第一句中清楚地回答,并提供了解决方案。您愿意详细说明吗?
blizzrdof77

2
你真的读过这个问题吗?关于是否可以修改符号链接而不是替换符号链接。您建议的“解决方案”是一个替换符号链接的脚本。
user2233709 '17

0

假设链接名称作为完成的结果而存在(过去):

 ln -s   /the/path/to/a/file   linkname

然后,有三种方法可以更改符号链接:

  • -f强制使用ln 甚至用于目录-n(可以重新使用inode):

    ln -sfn /some/new/path linkname
    
  • 删除符号链接并创建一个新的符号链接(甚至用于目录):

    rm linkname; ln -s /some/new/path linkname
    
  • 创建一个新的符号链接,然后mv它(即使目录也发生了原子变化):

    ln -s  /some/new/path newlinkname
    mv -fT newlinkname linkname             # linkname remains after the command
    
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.