Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

replace all symlinks with original

Tags:

bash

symlink

I have the following directory structure

/symdir   sym1 -> ../dir1   sym2 -> ../dir2   hello.txt 

And then

/dir1   some   files   here /dir2   more   files 

I would like to replace the symlinks in symdir (sym1, sym2) with the originals. I.e.

some_awesome_bash_func symdir symdir_output 

Would create

/symdir_output   /dir1     some     files     here   /dir2     more     files   hello.txt 

How would I accomplish this?

like image 432
Ken Hirakawa Avatar asked Aug 23 '11 20:08

Ken Hirakawa


People also ask

How do I remove all symlinks?

Conclusion. To remove a symbolic link, use either the rm or unlink command followed by the name of the symlink as an argument. When removing a symbolic link that points to a directory do not append a trailing slash to the symlink name.

Does rm remove symlinks?

The rm command is the dedicated tool for deleting files and directories from the system. Because the symlink itself is a file, we can use the rm command to remove it. The following rm command will remove the symlink. To remove multiple symlinks, use rm as you would to remove multiple files.

Can symlinks be copied?

We can use the -l option of rsync for copying symlinks. rsync copies the symlinks in the source directory as symlinks to the destination directory using this option. Copying the symlinks is successful in this case.

How do you fix a symbolic link?

The only way to fix these broken symlinks is by deleting them. Your system contains hundreds of dangling links and no one has the time to check for these links manually. In such cases, Linux tools and commands prove to be really helpful.


2 Answers

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.

like image 150
Julien Palard Avatar answered Oct 11 '22 14:10

Julien Palard


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.

like image 37
Jonathan Amend Avatar answered Oct 11 '22 13:10

Jonathan Amend