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 source
d) 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.