replace all symlinks with original

a related answer, this solution keeps the file at it's original place and creates a copy in place of the symlink

#/bin/bash

for f in $(find . -maxdepth 1 -type l)
do
    cp --remove-destination $(readlink -e $f) $f
done

You can do this easily with rsync:

rsync symdir/ symdir_output/ -a --copy-links -v

(-a means preserve basically every detail about the files, --copy-links overrides -a to turn symlinks into the real files/directories, and -v is for verbose)

Edit:

Sorry, my solution doesn't do exactly what you asked for. It will preserve the symlink's names instead of using the destination names. symdir_output would have sym1 and sym2 instead of dir1 and dir2 (though sym1 and sym2 would be a real copy of dir1 and dir2). Hope it still works for you.


Probably not the best way, but it works:

#!/usr/bin/bash

for link in $(find /symdir -type l)
do
  loc="$(dirname "$link")"
  dir="$(readlink "$link")"
  mv "$dir" "$loc"
  rm "$link"
done

My very personal trick for files (not directories):

sed -i '' **/*

Note that I'm using ** which uses the bash globstar option, you may have to enable it beforehand:

shopt -s globstar

How it works

I trick sed to do the job, by using an implementation detail of the sed inplace mode.

sed is a tool to edit streams of text. The -i option of sed means inplace, the empty string '' is the instruction set: so there's no instruction, sed will do nothing. **/* is a bash globstar pattern meaning "all files and all folders, at all depth, from here".

The algorithm sed uses to edit a file inplace is:

  • Create a temporary file as the output file,
  • for each line in the input file:
    • apply the transformation, write to the output file.
  • Move the output file over the input file.

As I'm asking no transformations (the empty string), the algorithm can be simplified as:

  • Create a temporary file,
  • copy the content of the original file to the temporary file
  • move the temporary file over the original file.

The temporary file is a real file, sed completly ignores that the input file was a symlink, it just reads it. So at the last step, when sed moves the temporary file over the real file, it "overwrite" the symlink with a real file, that's what we wanted.

This also explains why it won't work to transform a "symlink to a directory" to a real directory: sed works on file contents.

Tags:

Bash

Symlink