102

My basic understanding of a symlink is that it's a special file, a file that contains a string path to another file. The kernel's VFS abstracts a lot of that away but is there any reason why symlinks seem to be impossible to edit?

In other words: Can I edit a symlink? If not, why not?


I do understand that there are various ways of replacing symlinks (two alternatives are currently in the answers section) but it would be interesting to get an explanation on why replacement seems to be the only way to deal with symlinks. Why can't you just change where they point?

3
  • 1
    Your understanding is a bit limited; the only reason it's called a 'file' is because there's no better word for it.
    – Shadur
    Aug 30, 2013 at 9:23
  • 9
    Unlike the embarrassing atrocity that is the windows variant, posix-style symbolic links operate on/in the filesystem layer itself. The only way to edit one would be to edit the filesystem directly -- and it's generally not worth it.
    – Shadur
    Aug 30, 2013 at 9:27
  • 1
    @Shadur .lnk files are not really symlinks to begin with (and NTFS has had proper symlinks since Vista); they're more like shortcuts for executing commands, whether that is changing to a specific folder or starting a program with specific arguments and with a certain CWD.
    – JAB
    Apr 12, 2016 at 20:11

7 Answers 7

54

Given that -f just does a silent replacement, you can do an atomic replacement with mv -T (-T makes it work even if /loc.../link is a directory):

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

linkname is accessible throughout the process.

5
  • 10
    That does get you the atomic replacement, though you still are doing a replace rather than edit ( new link has a new inode number ).
    – psusi
    Aug 30, 2013 at 13:28
  • 2
    @psusi I completely agree, it's just a technically slightly better option than the other answer in some scenarios.
    – Oli
    Aug 30, 2013 at 13:34
  • If you're redirecting the link to another destination then changing it's inode number seems like a small change.
    – ams
    Aug 30, 2013 at 13:58
  • 4
    That assumes linkname is not a symlink to a directory. Use the -T option to mv if on GNU or -h if on FreeBSD to avoid that. Note that like ln -sf that does not preserve the permissions of the link (on systems where they are significant). Nov 7, 2014 at 14:48
  • Another solution for change symlink for directory is to use -n options e.g.: ln -sfn DESTINATION_DIRECTORY LINK_NAME . Read more on askubuntu.com/a/186227/69004
    – sobi3ch
    Nov 18, 2015 at 15:15
31

If by edit, you mean to change the file it points to, then yes you can:

$ 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

The -f parameter (--force) when passed to ln it causes it to call the unlink() system call right before symlink()

Taken from the following stack overflow answer.

4
  • 10
    I think it's questionable if this can be regarded as "edit", since unlink();symlink(); is not atomic, so there is a tiny tiny amount of time during which the link does not exist.
    – replay
    Aug 30, 2013 at 8:15
  • 2
    @mauro.stettler Yes, you are right. But I guess that this depends on your perspective. If you take only the end result into account, then maybe you could consider it as edited, no other things considered. Aug 30, 2013 at 8:17
  • 1
    The quoted section from the Unix Time Sharing System paper describes hard links. These are entirely different from the symbolic links (symlinks) the OP asked about. Aug 30, 2013 at 9:00
  • 6
    Note that it assumes test's target is not a directory. Otherwise ln -s -f .profile test would create a .profile symlink in that directory. GNU ln has a -T option to avoid that. Nov 7, 2014 at 14:13
10

Symbolic links need to be modified atomically. If you're halfway through writing them, they won't work. The content of a symbolic link is pretty small (at most 4095 characters on Linux: the maximum length of a path to a file), so there would be little point in editing part of a symbolic link at the kernel level. Therefore the kernel does not offer any interface to edit a symbolic link, only an interface to create a new one, the symlink system call (plus the generic interface unlink to remove any file).

The symlink system call only creates a new symbolic link, it does not remove any existing file. This is annoying, but consistent with other system calls to create files such as open (which can create a new file or truncate an existing file, but not replace an existing file by a newly-created file) and mkdir.

In the shell, as you've discovered, while you can't replace a symbolic link atomically with the ln command (ln -sf unlinks the previous file then creates the symbolic link), you can do it by first creating a symbolic link under a temporary name and then moving it into place.

tmp=$(TMPDIR=$(dirname -- "$link") mktemp)
ln -sf -- "$target" "$tmp"
mv -f "$tmp" "$link"
1
  • 2
    mv -f (like ln -sf) will not do what you want if $link points to a directory. GNU ln and mv have a -T for that. mv (rename system call) will always change the inode of $link while ln -sfT (unlink+symlink) might reuse the same. Nov 7, 2014 at 14:07
2

Assume linkname exists as the result of having done (in the past):

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

Then, there are three ways to change the symlink:

  • Use ln with -f force and even for directories -n (inode could get reused):

    ln -sfn /some/new/path linkname
    
  • Remove the symlink and create a new one (even for directories):

    rm linkname; ln -s /some/new/path linkname
    
  • create a new symlink, then mv it (atomic change even for directories):

    ln -s  /some/new/path newlinkname
    mv -fT newlinkname linkname             # linkname remains after the command
    
1

Technically, there's no built-in command to edit an existing symbolic link. It can be easily achieved with a few short commands.

Here's a little bash/zsh function I wrote to update an existing symbolic link:

# -----------------------------------------
# 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"
}
5
  • 1
    Sorry, but you “answer” is only remotely-related to the question asked. Nov 26, 2017 at 23:01
  • 1
    Hi @user2233709 - the user's question "How can I edit symlinks?" was clearly answered in the first sentence as well as by providing a solution. Would you care to elaborate? Nov 30, 2017 at 19:38
  • 4
    Did you really read the question? It’s about whether it is possible to modify a symlink, rather than replace it. Your proposed “solution” is a script that replaces a symlink. Nov 30, 2017 at 22:47
  • 1
    Saying that this answer “is only remotely-related to the question asked” is unduly harsh.  blizzrdof77 says that it’s impossible to do what the question asks for; that is an acceptable answer.  “Your proposed “solution” … replaces a symlink.”  The same is true for all the other answers (except for the one that ‘‘actually shows’’ how to edit a symlink, which is wrong). Dec 3, 2020 at 0:22
  • The bad news is that this is just a more verbose, less careful version of Gilles’s answer. Dec 3, 2020 at 0:22
1

one can edit the target value using 'rename -s'. an absolute path or an expression can be used.

synopsis:

rename -s old_target_or_expression new_target_or_expression link_name

example

$ ln -s /home/sr/tmp/bla foo # create a symlink
$ ls -l foo
lrwxrwxrwx 1 sr sr 16 Jun  4 14:41 foo -> /home/sr/tmp/bla
$ rename -s /home/sr/tmp/bla /home/jn/tmp3/blabla foo # replace the target using the absolute path
$ ls -l foo # it works!
lrwxrwxrwx 1 sr sr 20 Jun  4 14:43 foo -> /home/jn/tmp3/blabla
$ rename -s jn/tmp3/ mr/tmp4/ foo # replace the target using an expression (only a part of the string)
$ ls -l foo # it works again!
lrwxrwxrwx 1 sr sr 20 Jun  4 14:44 foo -> /home/mr/tmp4/blabla

man rename

-s, --symlink
           Do not rename a symlink but its target.
0

with Vifm

Vifm the file manager has a default key mapping (shortcut) to change where a symlink points to:

c+l

The mnemonic is change link.

Here's a cheetsheet that includes this mapping.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .