Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have a directory tree which has a bunch of symbolic links to files under /home... however, I have moved /home to /mnt/home and need a way to "relink" all of the symlinks. Does such functionality exist or do I need to write a script to do so?

As an example, I have something like the following:

[root@trees ~]# ls -l /mnt/home/someone/something
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/e

/mnt/home/someone/something/subdir:
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/subdir/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/subdir/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/subdir/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/subdir/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/subdir/e

I want a command which will find all the symlinks and relink to the same places but underneath /mnt/home instead of /home

Does such a command exist?

share|improve this question

3 Answers 3

up vote 27 down vote accepted

There is no command to retarget a symbolic link, all you can do is remove it and create another one. Assuming you have GNU utilities (e.g. under non-embedded Linux or Cygwin), you can use the -lname primary of find to match symbolic links by their target, and readlink to read the contents of the link. Untested:

find /mnt/home/someone/something -lname '/home/someone/*' \
     -exec sh -c 'ln -snf "$0" "/mnt$(readlink "$0")"' {} \;

It would be better to make these symbolic links relative. Before the move, or after you've restored valid links as above, run symlinks -c /mnt/home/someone/something to convert all absolute symlinks under the specified directory to relative symlinks unless they cross a filesystem boundary. The symlinks utility is by Mark Lord, and offered by many distributions; if yours doesn't have it, grab the source from e.g. Ubuntu.

share|improve this answer
    
Awesome, that did the trick! Thanks again Gilles!! –  Josh Aug 9 '11 at 12:09
1  
Good lord man, did you just invent that oneliner or pick it up from another source. Regardless, this is why we need the stacks, because there is NO way I would've known about a command like that without a day's worth of reading ... –  jcolebrand Aug 9 '11 at 14:12
2  
Gilles is to unix commands what Jon Skeet is to C# –  Josh Aug 9 '11 at 21:46
    
Gilles isn't human. I decided that a long time ago... –  MaxMackie Dec 30 '11 at 16:17
    
No offense, this is a great one-liner, but Bash's string substitution could probably do some magic w.r.t. the path change and would be easier. –  0xC0000022L Feb 8 '12 at 20:30

I know this is not exactly what the author is requesting but it seems they already have their answer so I'm adding this for others like me who stumble upon the question.

The following should help if a more flexible solution is required such as having a bunch of broken symbolic links which can be fixed by replacing part of the symbolic link's targets.

eg. After a change of username, to replace the old username with the new username in the target of many links, after the move had already been done. Create a script called replace-simlinks shown below:

#!/bin/bash
link=$1
# grab the target of the old link
target=$(readlink -- "$1")

# replace the first occurrence of oldusername with newusername in the target string
target=${target/oldusername/newusername}

# Test the link creation
echo ln -s -- "$target" "$link"

# If the above echo gives the shows the correct commands are being issued then uncomment the following lines and run the command again
#rm $link
#ln -s "$target" "$link"

and call it with the following command:

find /home/newusername/ -lname '/home/oldusername/*' -exec ~/bin/replace-simlinks {} \;

Hope this help somebody

edit: Thanks Gilles for the kickstart on this script and the tip about using the symlinks script to make the links relative.

share|improve this answer
1  
This helped me very much for a similar problem that was related to a samba dfs share. –  drescherjm Feb 18 '13 at 11:47
    
Very glad to hear it. :) –  Gerry Feb 18 '13 at 13:10

Create /home as a symlink to /mnt/home, and all the existing symlinks will be valid again.

share|improve this answer
1  
Bind-mounting often tends to be less fragile than symlinks in scenarios where programs are aware of symlinks and act differently depending on the fact ... –  0xC0000022L Feb 8 '12 at 20:27

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.