Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

I have a web app that has a bunch of symbolic links in subdirectories throughout it. I need to move the app to another directory structure, and I need to update all the symlinks to point to the new path. For example:

Old Dir: /home/user/public_html/dev
New Dir: /home/user/public_html/qa
Old Symlink: /home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/dev/images
New Symlink: /home/user/public_html/qa/multisites/slave01/images -> /home/user/public_html/qa/images

The problem is that there's a lot of these scattered throughout various directories. How can I recursively search from the root and recreate all symlinks pointing to /dev/ with /qa/?

share|improve this question

3 Answers 3

up vote 3 down vote accepted

This bash command should do it for you:

find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' -printf 'ln -nsf $(readlink %p | sed s/dev/qa/) $(echo %p | sed s/dev/qa/)\n' > script.sh

It uses find to identify all files in the qa directory that are symbolic links with a target that's in the dev directory, and for each one, it prints out a bash command that will replace the link with a link to the equivalent path in qa/. After you run this, just execute the generated script with

bash script.sh

You might want to examine it manually first to make sure it worked.

Here's the find command broken up on to multiple lines for easier viewing:

find /home/user/public_html/qa/ -type l \
  -lname '/home/user/public_html/dev/*' -printf \
  'ln -nsf $(readlink %p|sed s/dev/qa/) $(echo %p|sed s/dev/qa/)\n'\
 > script.sh
share|improve this answer
    
This creates an empty script.sh. And running the find command as so: find /home/user/public_html/qa/ -type l -lname '/home/user/public_html/dev/*' doesn't output anything. –  ggutenberg Jun 29 '10 at 4:25
    
You did remember to change the paths to the actual ones on your filesystem, right? What happens if you run just find /home/usr/public_html/qa/ -type l? If that doesn't find the links, something very weird is going on with your system. –  David Z Jun 29 '10 at 5:34
    
Yes, "find /home/user/public_html/qa/ -type l" outputs the links. But adding the -lname parameter it doesn't output anything. –  ggutenberg Jun 30 '10 at 3:34
    
Actually, on further testing it looks like this is working. Not sure what I was doing wrong yesterday, but seems ok now. Thanks. –  ggutenberg Jun 30 '10 at 3:41
    
Huh, weird. Well, if you ever figure out what was going wrong, put a comment here. I'm curious. –  David Z Jun 30 '10 at 3:54

In case anyone else finds this when searching for a solution: Create a file named "linkmod.sh" containing:

#!/bin/sh
PATTERN1=`echo "$2"`
PATTERN2=`echo "$3"`
LINKNAME=`echo "$1"`
OLDTARGET=`readlink "$1"`
NEWTARGET=`echo "$OLDTARGET" \
| sed -e 's/'"$PATTERN1"'/'"$PATTERN2"'/'`
echo ln -nsf "$NEWTARGET" "$LINKNAME"

and run

find . -type l -print0 | xargs -0IX linkmod.sh X "pattern1" "pattern2"

You can ofc use the -lname option in find if needed.

NOTE: you have to use 2x \ in the patterns before any characters that require \ in sed, since echo removes one. For example

find . -type l -print0 | xargs -0IX linkmod.sh X "folder\\ name\\/file" "folder2\\ name\\/file"

Remove the echo from the last line if the ln commands are correct.

share|improve this answer

I ended up writing a command-line PHP script which seems to do the trick.

<?php
//Run via command-line
$dir = new RecursiveDirectoryIterator('.');
foreach(new RecursiveIteratorIterator($dir) as $file) {
    //$link = readlink($file);
    if(is_link($file)) {
        $old_link = readlink($file);
        $new_link = str_ireplace("/joomla/", "/qa/", $old_link);
        if($new_link != $old_link) {
            exec('rm "'.$file.'"');
            exec('ln -fs "'.$new_link.'" "'.$file.'"');
            $new_link = readlink($file);
            if($new_link == $old_link) {
                echo $file."\t".$old_link."\t".$new_link."\n";
            }
        }
    }
}
?>
share|improve this answer

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.