5

There are lots of broken links in my system. I wrote a script to relink all broken links. But, after the scripts runs, find would again show me that the links still exists.

This is my code:

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

After running the command above, I search for broken links and still find them:

find . -type l | xargs file | grep broken 

What am I doing wrong?

5

The first problem is that your find command will only find links that used full paths, not relative ones. To illustrate:

$ ln -s /home/terdon/foo/NonExistantFile foo
$ ln -s NonExistantFile bar

$ tree
.
|-- bar -> NonExistantFile
`-- foo -> /home/terdon/foo/NonExistantFile

In the example above, I created two broken links. The first used an absolute path and the second, a relative one. If I now try your find command (having it echo the relinking command instead of running it so we can see what it's doing), only one of the two will be found:

$ find . -lname '/home/terdon/*' -exec \
    sh -c 'echo ln -snf "/home$(readlink "$0")" "$0"' {} \; 
ln -snf /home/home/terdon/foo/NonExistantFile ./foo

The second issue is that your path is wrong. You are recreating links as "/home$(readlink "$0")" "$0". The readlink command will already show the full path so adding /home to it results in /home/home/... which is not what you want.

More importantly, what you are attempting is not possible. If a link is broken, that means that its target does not exist. Since the target doesn't exist, you can't simply relink the file, there's nowhere to link it to. The only thing you could do is recreate the link's target. This, however, is unlikely to be very useful since it would simply make your broken links point to new, empty files. If that is indeed what you want to do, you could try

 find . -type l -exec sh -c 'touch "$(readlink "{}")" ' \; 

Finally, you might want to create a more complex script that i) finds all broken links ii) searches your machine for files with the same name as the target of the link iii) presents you with a list of them and iv) asks you which one it should now link to.

  • Your find might almost be that more complex script you describe. Have you ever played around with the -ok find action? It's basically like -exec except it prints a user specified prompt + targeted filename to stderr and awaits confirmation before running the command. If the answer is a negative it continues processing with the next match it finds. – mikeserv Apr 4 '15 at 12:18
  • 1
    @mikeserv yes, that's a step in the right direction but I'm thinking more of those cases where there are multiple hits for the target name and the script would have to present you with all of them and ask which one you want the link to point to. – terdon Apr 4 '15 at 12:23
  • yeah - it's no fun for sure. this is a good answer - and that's a good point. maybe find ... -ok find .... -ok .... would be a step further - but it would definitely be more complicated. In my (biased) opinion, people would be a lot better off if they mounted their indirection requirements and detailed the whole thing in fstab rather than sprinkling little problems all over their fs. At least on linux anyway. – mikeserv Apr 4 '15 at 12:32
1

There are lots of broken links in my system. I wrote a script to relink all broken links. But, after the scripts runs, find would again show me that the links still exists...

This one liner may be of interest on GNU Linux systems. I believe it came from @Giles but I can't find the reference at the moment.

find -xtype l -delete

It recursively finds and deletes broken soft links.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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