Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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

share|improve this question
What problem are you trying to solve? – Daniel Beck Jun 28 '11 at 19:46
I have a bunch of symbolic links to another drive. I need move all files off of that drive that are referenced elsewhere so I can remove it. – Marty Trenouth Jun 28 '11 at 19:49
up vote 10 down vote accepted

For some definitions of "easy":

set -e
for link; do
    test -h "$link" || continue

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

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

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

share|improve this answer
+1 for completed solution, nice work! – Doc Jun 28 '11 at 20:44
Thanks for the edit, anon, but the script does handle filenames with spaces just fine, by quoting variables in all necessary places. Changing "$var" to "${var}" is a noop in sh/bash. I removed the one bashism ([[), the rest is compatible with POSIX sh. – grawity May 6 '14 at 5:46
An even more robust method for handling symlink failures is to cp to a temporary file in the same directory then mv -f that temporary file into the original. This should guard against problems like people holding down Ctrl-C or the filesystem filling up between the rm and cp commands (thus preventing even the new ln from working). Temporary filenames are easy to spot with ls -a for later cleanup if needed. – Mr Fooz Aug 5 '15 at 16:46

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
share|improve this answer
I love your solution, but I don't understand the last part of your message. For me you should do : tar -hcf - sourcedir | tar -xf - -C newdir – Seb DA ROCHA Apr 9 '12 at 13:52
Agreed, this answer would need updating as per comment. – astabada Jun 9 '14 at 13:44
cp -L is the simpler solution – plesiv Sep 18 '15 at 13:25

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.

share|improve this answer
Thanks - almost what I needed: I had to do something like: cp -L files tmp/ && rm files && cp tmp/files . If you clarify, you'll probably help more people... – sage Sep 18 '13 at 0:05

"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 ./ {} \;

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] >", etc) then pass that file in to a script you've written to handle copying over the original gracefully.

share|improve this answer
? A bit generic - can you elaborate? – Linker3000 Jun 28 '11 at 20:04
+1 for the elaboration! – Linker3000 Jun 28 '11 at 20:30
The syntax is -exec ./ {} \; – grawity Jun 28 '11 at 20:37
+1 @grawity - thanks – Doc Jun 28 '11 at 20:44
This is go to find the items and the one marked as the answer is used to replace the links! – Marty Trenouth Jun 28 '11 at 22:07
find . -type l -exec cp --dereference --recursive '{}' '{}'.dereferenced \;

Will make a copy of each symlinked file/folder in <filename>.dereferenced, which is safer (if less convenient) than just replacing them directly. Moving the copied data to the symlinks' filenames is left as an exercise for the reader.

share|improve this answer

Lot's of good answers there but I since you were looking for something easy

for i in *; do link=$(readlink $i) && rm $i && mv $link $i; done
share|improve this answer
A little enhancement will help to find symbolic links: for lnk in `find . -type l`; do src=$(readlink $lnk) && rm $lnk && mv $src $lnk; done (not tested with hierarchy though, be careful with backticks) – Roman Susi Feb 13 '14 at 8:03

I had the same problem with gwenview copying links when you would normally expect it to follow the link and copy the file.

What I did to 'clean' the directory by following all the links and copying all the pointed-to files to the directory, was create a scratch directory, run e.g.

"for file in `ls`; do cp -L $file scratchdir/$file; done; mv scratchdir/* ./" 

this is too dangerous to put in a script as there is no checking but it fixed my problem.

share|improve this answer

Using some of the previous ideas, the following command will recursively replace every symlink with a copy of the original:

find . -type l -exec bash -c "echo 'Replacing {} ...';  cp -LR '{}' '{}'.dereferenced;  rm '{}';  mv '{}'.dereferenced '{}'" \;
share|improve this answer

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .