Sometimes, I use VirtualBox with a Windows guest system under a Linux Mint host system, with a shared directory ~/_D corresponding to my D:\-drive in Windows. However, there are many symbolic links to directories below ~/_D, some of which are even circular, which causes some Windows processes not to work as I need.
Therefore I am working on a bash script that temporarily removes all symlinks below ~/_D and at the same time creates another script that can restore those symlinks later when I am done with my work on Windows.
However, I am struggling with writing the output of the find ... -exec readlink {} \; command into a file without newlines. My script currently goes like this:
#! /bin/bash
cd ~/_D
echo "# restores all symlinks deleted by ~/bin/symlink.remove" > symlinks.restore
echo >> symlinks.restore
find . -type l -exec readlink {} \; -print -exec echo "" \; -exec rm {} \; >> symlinks.restore
echo >> symlinks.restore
echo "# run emacs command sd-restore-symlinks on this file" >> symlinks.restore
chmod u x symlinks.restore
echo to restore symlinks, run emacs command sd-restore-symlinks on ~/_D/symlinks.restore
echo then run ~/_D/symlinks.restore
Instead of awkwardly using an emacs search-and-replace-function just for rearranging the output for each symlink from two lines, separated by an empty line, into one line, resulting in lines such as ln -s "../.Events.OLD" "./Events/Events.OLD" (mind the quotes to avoid havoc with possible spaces in filenames), I would love to generate the output file symlinks.restore directly from my bash script.
However, using hacks like: find -type l -exec echo -n $(readlink {}) \; does not work, probably because{} is not accessible as alias for the current file within $(), also not when quoted \{\}.
I guess that some smart combination of -printf or -print0 actions of find, and/or perhaps sed, can do the trick, but this goes beyond what I can achieve.
Also, perhaps there are already tools to temporarily remove and then restore all symlinks below a certain directory?
Any ideas?
CodePudding user response:
You may use this find command to create restore script:
find . -type l -exec bash -c '
for symlnk; do
printf "ln -s %q %q\n" "$(readlink "$symlnk")" "$symlnk"
done' _ {} > symlinks.restore
The restore script (symlinks.restore) must be run (or sourced) from the same directory as the find command is run.
CodePudding user response:
With -printf something like.
find . -type l -printf 'ln -s "%p" "%l"\n' > symlinks.restore
It has limitations and it is not bullet proof, which was mentioned by M. Nejat Aydin
CodePudding user response:
Thanks to both, M. Nejat Aydin and Jetchisel.
The latter solution worked best for me, with some adjustments (quotes, changed order of parameters %p and %l, and added rm command).
My script now reads:
#! /bin/bash
cd ~/_D
printf "#! /bin/bash\n\n# restores all symlinks deleted by ~/bin/symlink.remove\n# has to be executed in _D\n\n" > symlinks.restore
find . -type l -printf 'ln -s "%l" "%p"\n' -exec rm {} \; >> symlinks.restore
chmod u x symlinks.restore
This works fine, even with spaces in filenames.
Differently from my earlier comments, the other solution also works without producing literal backslashes in the link targets; the relevant command I now successfully used is
find . -type l -exec bash -c '
for symlnk; do
printf "ln -s \"%q\" \"%q\"\n" "$(readlink "$symlnk")" "$symlnk"
rm $symlnk
done' _ {} >> symlinks.restore
Thanks again to all who responded.
