0

I currently have an issue that I'm struggling to resolve regarding symbolic links. I am migrating backups from a Windows server to Debian via rsync, and it seems there are no options to have the symbolic links be recreated to point to the equivalent locations in the destination.

All the solutions to recursively fix symbolic links I have found, all seem to only work if the links all point to targets in the same file system.

The source destination is an ntfs partition via iscsi that my windows machine uses for backups, So changing all the symbolic links in the source location to relative before the transfer is not an option. The source must be left untouched and considered read only, Until The new backup server is up and running, And tested to be working.

What I'm looking for is a solution to reconnect the symbolic links at the destination, As Demonstrated below.

symlinks at source: /mnt/fs1/backup/v1/linkToDir1 -> /mnt/fs1/backup/data/dir1 /mnt/fs1/backup/v2/linkToDir2 -> /mnt/fs1/backup/data/dir2 symlinks at destination: /mnt/fs2/backup/v1/linkToDir1 -> /mnt/fs2/backup/data/dir1 /mnt/fs2/backup/v2/linkToDir2 -> /mnt/fs2/backup/data/dir2 

At the moment, This is all i am getting.

symlinks at destination: /mnt/fs2/backup/v1/linkToDir1 -> /mnt/fs1/backup/data/dir1 /mnt/fs2/backup/v2/linkToDir2 -> /mnt/fs1/backup/data/dir2 

As you can see, the problem is that the symlinks are pointing to the first file system, Not to its corresponding target in the new location.

I found this command as its description sounded like it was just what I needed. As stated by the poster, it would also be able to handle special characters and spaces.

find . -type l -exec printf "ln --no-target-directory -srf -- %q %q\n" {} {} \; | bash 

Getting rid of | bash To preview the output, it looked like it was going to work

ln --no-target-directory -srf -- ./GAMEBOX-V2/.directory_pool/F1/F1RgpLPbLL17134735891344751328/aida32pe_393 ./GAMEBOX-V2/.directory_pool/F1/F1RgpLPbLL17134735891344751328/aida32pe_393 

But looking at the links, It made itself relative from file system 1 mount point.

symlinks: /mnt/fs2/backup/v1/linkToDir1 -> /../../fs1/backup/data/dir1 /mnt/fs2/backup/v2/linkToDir2 -> /../../fs1/backup/data/dir2 

Can anyone think of a solution that exists that can, recursively find absolute Symlinks starting at the directory of interest, Read them, and chop off the beginning of the path to make it relative to its new home and replace the old dangling symlink.

Am I on the right track and just got something wrong, or have I completely misunderstood somthing and ended up far out into the woods?

Even if there's a copy tool that does this while copying, I wouldn't mind transferring all the data again if it just means it works. The backup software I'm using is urbackup, and the only way to get the new backup server operational is for the simlinks to be fixed, as it must maintain its directory structure.

2 Answers 2

2

I would like to thank @larsks for his contribution.

Unfortunately, I will not be able to test it as I already processed the links thanks to this article. I will present the solution I found as well for people to determine what works best for them. But both solutions look like they do the same in a different way.

The command I used was as follows.

$ find /mnt/fs2/backup/ -xtype l -exec bash -c 'target="$(readlink "{}")"; link="{}"; target="$(echo "$target" | sed "s|/mnt/fs1|/mnt/fs2|g")"; echo "ln -Tfs "$target" "$link""' \; 

It uses find to look for symbolic links with -xtype l and -exec to execute the next commands for every instance found. It also uses sed instead to modify the strings.

At first I thought it wouldn't work for me, as the example showed the syntax as being the following:

sed “s/StringToLookFor/ReplaceWithThis/g”

The slashes would have been a problem for working with directories. But it turns out you can use anything as a delimiter, as long as it is The next character after s. so I swapped it out with pipe "|" as I knew that would not be used in any directory or file names.

sed "s|/mnt/fs1|/mnt/fs2|g" 

I ran it and it looked like it worked like a treat, so I removed the echo and double quotes on the last command that was essentially making it a dry run.

$ find /mnt/fs2/backup/ -xtype l -exec bash -c 'target="$(readlink "{}")"; link="{}"; target="$(echo "$target" | sed "s|/mnt/fs1|/mnt/fs2|g")"; ln -Tfs "$target" "$link"' \; 

All the symbolic links are now fixed and pointing to their correct locations in the new directory location.

Claire, the author of the article, breaks down and explains every step of the commands Quite clearly. Very helpful if you'd like to get your head around what the command is doing step by step if your a linux novice, like my self.

0

It looks like your goal is to replace /mnt/fs1 with /mnt/fs2 in all symlinks found under /mnt/fs2. You could do something like this:

find /mnt/fs2 -type l -execdir \ sh -c 'readlink $1 | grep -q /mnt/fs1' -- {} \; -print0 | xargs -0 bash -c 'old="$(readlink "$1")"; new="${old/fs1/fs2}"; ln -sf "$new" "$1"' -- 

That uses find to find all the symlinks under /mn/fs2, and then for each symlink it reads the link target with readlink and pipes that to grep to determine whether or not we are interested in the link.

We take the list of links that contain /mnt/fs and pipe that through xargs, which for each link runs a shell script that reads the link target, replaces fs1 with fs2, and then replaces the link.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.