Is it possible to edit a symlink with a text editor?
Asked Answered
E

4

19

When we create a symlink, the number of bytes the symlink takes up is exactly the length of the origin it points to. For instance,

$ ln -s dest link1
$ ln -s longer_dest link2
$ ls -l
lrwxrwxrwx 1 username  4 Mar 26 20:21 link1 -> dest
lrwxrwxrwx 1 username 11 Mar 26 20:21 link2 -> longer_dest

where link1 takes up 4 bytes, which is the length of dest; link2 takes up 11 bytes, which is the length of longer_dest. Therefore, symlinks are in fact no more than the destination path stored in plain text. So I am wondering if it is possible to edit (the destination) of a symlink in text editors, preferably Emacs. I googled for a while and couldn't find anyone talking about this. Note that this question is purely out of curiosity; I know full well that I can overwrite a symlink by ln -f -s.

Extent answered 27/3, 2014 at 3:29 Comment(1)
For those who voted close, I believe this is a valid, clearly stated question; and although it is not directly programming-related, it is of interest to programmers, plus there are a ton of this kind of questions here—just look at related questions.Extent
T
6

Yes, in Emacs this is possible in dired-mode, specifically wdired (writable dired) mode.

Note, dired and wdired both are built-in packages.

Here's an example...

wdired editing a symlink

(BTW: I'm using Smex to give Emacs M-x command search & execute a more ergonomic UI + fuzzy matching)

Total answered 25/3, 2018 at 2:59 Comment(2)
Text version of how to do this: once in dired, C-x C-q to enter the wdired mode. Make the desired changes in the dired buffer. Then C-c C-c to apply the changes.Tugboat
BTW since S-w is unbound (shift w) I use that in the dired-mode-map for starting wdired-change-to-wdired-mode. C-x C-s also saves changes made in wdired-mode which is easier on your muscle memory.Total
F
6

It's possible in principle, but the editor would need to specifically support it, since reading the destination of a symlink requires a special system call: readlink().

You're unlikely to find any editors that actually do this, since it's not very useful, and conflicts with what most users want the editor to do when asked to open a symlink: open the file that it points to.

Froufrou answered 27/3, 2014 at 3:51 Comment(1)
Thanks, this sounds reasonable. I voted up but won't accept just yet.Extent
T
6

Yes, in Emacs this is possible in dired-mode, specifically wdired (writable dired) mode.

Note, dired and wdired both are built-in packages.

Here's an example...

wdired editing a symlink

(BTW: I'm using Smex to give Emacs M-x command search & execute a more ergonomic UI + fuzzy matching)

Total answered 25/3, 2018 at 2:59 Comment(2)
Text version of how to do this: once in dired, C-x C-q to enter the wdired mode. Make the desired changes in the dired buffer. Then C-c C-c to apply the changes.Tugboat
BTW since S-w is unbound (shift w) I use that in the dired-mode-map for starting wdired-change-to-wdired-mode. C-x C-s also saves changes made in wdired-mode which is easier on your muscle memory.Total
V
2

As per the Storage of symbolic links section in Wikipedia's article Symbolic Links, the symlinks are stored in an inode. This inode is a data structure containing several information about the file in question - as per this thread, the touch command can be used to change some of its values. So, it may not be possible to modify it by using a text editor, due to the problems that @Wyzard mentioned, but it might be modifiable by using some other command-line tools like touch.

I hope this helps!

Votary answered 27/3, 2014 at 4:5 Comment(0)
B
2

It's not possible directly, as others have already pointed out, but of course you can write a script for it. Here's one I came up with when I had to change lots of symlinks

#! /bin/bash

tmp=$(mktemp)
trap "rm $tmp" EXIT

while [ ! -z "$1" ]; do
    filename="$1"; shift
    if [ ! -h "$filename" ]; then
        echo "Not a symlink: $filename";
        continue
    fi
    stat -c "%N" "$filename" >> $tmp
done
emacs $tmp

while read filename linkname; do
    ln -sf "$linkname" "$filename"
done < <(sed "s/'\(.*\)' -> '\(.*\)'/\1 \2/" $tmp)

It worked for me, but it's certainly not perfect, so use at your own risk...

Braddy answered 31/1, 2017 at 11:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.