Replace Symbolic Links with Files

Is there an easy way to replace all symbolic links with the file they link to?


For some definitions of "easy":

#!/bin/sh
set -e
for link; do
    test -h "$link" || continue

    dir=$(dirname "$link")
    reltarget=$(readlink "$link")
    case $reltarget in
        /*) abstarget=$reltarget;;
        *)  abstarget=$dir/$reltarget;;
    esac

    rm -fv "$link"
    cp -afv "$abstarget" "$link" || {
        # on failure, restore the symlink
        rm -rfv "$link"
        ln -sfv "$reltarget" "$link"
    }
done

Run this script with link names as arguments, e.g. through find . -type l -exec /path/tos/script {} +


If i understood you correctly the -L flag of the cp command should do exactly what you want.

Just copy all the symlinks and it will replace them with the files they point to.

cp -L files tmp/ && rm files && mv tmp/files .


Might be easier to just use tar to copy the data to a new directory.

-H      (c and r mode only) Symbolic links named on the command line will
        be followed; the target of the link will be archived, not the
        link itself.

You could use something like this

tar -hcf - sourcedir | tar -xf - -C newdir

tar --help:
-H, --format=FORMAT        create archive of the given format
-h, --dereference          follow symlinks; archive and dump the files they point to

"easy" will be a function of you, most likely.

I'd probably write a script that uses the "find" command line utility to find symbolically linked files, then calls rm and cp to remove and replace the file. You'd probably do well to also have the action called by find check that there's enough free space left before moving the sym link too.

Another solution may be to mount the file system in question through something that hides the sym links (like samba), then just copy everything out of that. But in many cases, something like that would introduce other problems.

A more direct answer to your question is probably "yes".

Edit: As per the request for more specific info. According to the man page for find, this command will list all sym link files in to a depth of 2 directories, from /:

find / -maxdepth 2 -type l -print

(this was found here)

To get find to execute something on finding it:

find / -maxdepth 2 -type l -exec ./ReplaceSymLink.sh {} \;

I believe that'll call some script I just made up, and pass in the file name you just found. Alternatively, you could capture the find output to file (use "find [blah] > symlinks.data", etc) then pass that file in to a script you've written to handle copying over the original gracefully.