One of the otherwise great answers states:
There is no command to retarget a symbolic link, all you can do is remove it and create another one.
The rename
command's -s
option will "rename a symbolic link target, not the symbolic links itself". It will also operate on multiple symbolic links at once. This seems to be the behavior the OP requested.
The rename
command is part of the util-linux package and is available from https://www.kernel.org/pub/linux/utils/util-linux/. It has been available since at least June 2011.
OP said:
I want a command which will find all the symlinks and relink to the same places but underneath /mnt/home instead of /home
The rename
command can do that and it can do it for multiple files (symbolic links) at once. Unfortunately, the OP uses a, b, c, d, e as example filenames. Those names don't seem realistic, so I won't use them in my answer. (If the OP is working with multiple subdirectories the solution may be more complex than what I'm presenting, but I still think rename
is a very convenient tool for this general requirement, and it can be combined with other tools such as find ... -execdir ...
.)
I did just use rename
to fix multiple broken symbolic links as shown below. This is the "before" listing from ls
:
second.files -> first.files.tar.zst
second.files.sig -> first.files.tar.zst.sig
The targets first.files.tar.zst*
do not exist. This is analogous to the OP's situation.
I used this command to fix all the broken symbolic links:
rename -s 'first' 'second' second.files*
The two single-quoted arguments apply to the target. The last argument, second.files*
selects the links upon which to operate. Those symbolic links are not renamed. Due to the use of the -s
option, the search/replace operation is performed on the targets.
Here is the "after" listing from ls
after running the above rename
command
second.files -> second.files.tar.zst
second.files.sig -> second.files.tar.zst.sig
The links have been "relinked" and they work correctly now.
Here is an example of using it to relink any symbolic links that has the pattern "somelinks*" in its name where we want to change the target location from /home
to /mnt/home
.
rename -s '/home' '/mnt/home' somelinks*
The man page suggests that the single quotes are mandatory. In this case, multiple broken links matching the pattern somelinks*
were fixed, which means they were retargeted to point to the correct location. The symbolic links name itself was not changed, but the file it pointed to was changed.
It would be better to use relative symbolic links.
I'm sure the person who wrote the above statement had good justification. However, we actually prefer absolute symbolic links in our environment (where we utilize network shares). If the directories on the clients and fileserver are laid out consistently, absolute symbolic links will work across file systems and even over network shares. Within our team, they provide for a very consistent and robust navigation solution. We can all share consistent file paths with each other. Haven't had problems with this approach over the last 8 or so years. But if your situation is different, by all means consider relative symlinks as Gilles suggested.
/mnt
to a path; you need no fancier string operation than concatenation. – Gilles 'SO- stop being evil' Feb 08 '12 at 20:41ln -snfr
(adding the-r
option) instead ofln -snf
do that? That way you don't have to runsymlinks -c
afterwards. – Gabriel Staples Jan 17 '23 at 07:07-v
) vialn -snfrv
, shows that in that particular usage ofln
, if the symlink is already-existing, running the command, even with force (-f
), is not enough to convert from absolute to relative. Rather, you must remove the symlink 1st. So, this works to convert a symlink from absolute to relative:SYMLINK_PATH="path/to/symlink"; TARGET_PATH="$(readlink "$SYMLINK_PATH")"; rm "$SYMLINK_PATH"; ln -svrf "$TARGET_PATH" "$SYMLINK_PATH"
. Therefore, in your answer, you'd have to read the symlink w/readlink
to get the target, thenrm
it, then recreate it. – Gabriel Staples Jan 17 '23 at 17:45symlinks -c
after-the-fact. – Gabriel Staples Jan 17 '23 at 17:48ln -r
didn't exist yet when I wrote this answer (added in GNU coreutils 8.16 released in March 2012). I don't see whyln -snfr
wouldn't work: I tried on an absolute link and it did convert it to relative. There was a bug that this didn't work originally, but it was fixed in coreutils 8.22 released in December 2013. – Gilles 'SO- stop being evil' Jan 17 '23 at 21:01ln --version
ln (GNU coreutils) 8.32
. 1) Create an absolute symlink to a directory:ln -sf ~/some_dir some_dir
.ls -alF some_dir
shows it points to an absolute path. 2) Now try to replace it with a relative symlink:ln -srf ~/some_dir some_dir
. That doesn't work as I'd expect! It creates a symlink to itself insidesome_dir
instead of replacing thesome_dir
symlink with a relative one.You have torm
the symlink first, or doln -srf ~/some_dir .
instead. – Gabriel Staples Jan 18 '23 at 22:51-n
option toln
(which you correctly included in your original comment here). – Gilles 'SO- stop being evil' Jan 19 '23 at 11:00-n
did before. I just copy-pasted it from your answer. Now I get it. – Gabriel Staples Jan 19 '23 at 16:23