Automatically symlink directory files into another directory
Anytime I add something to ~/config/
, I would like it to be symlinked into ~
. I don't want to run ln -s
every time.
Solution 1:
There is iwatch
utility, it can do this. In my Ubuntu I have installed iwatch
package to get it. It may be used as a daemon or a command line tool.
I cannot guarantee the solutions below are foolproof and well written. Treat them as a proof of concept.
Command line
In my tests I did not manage to make the single instance of iwatch
itself perform one action when a file is created but another action when it is removed. Maybe you can do this somehow. I decided to parse its output instead and then decide (case
statement) what to do. Run this:
cd ~/config
iwatch -e create,moved_to,delete,moved_from -c "printf '%s %s\n' %e %f" ./ |
while read -r e f ; do
f="$(basename "$f")"
case $e in
*IN_CREATE|*IN_MOVED_TO)
ln -s "config/$f" "../$f"
;;
*IN_DELETE|*IN_MOVED_FROM)
test -L "../$f" && rm "../$f"
esac
done
Play with touch
, mkdir
, mv
, rm
etc. in ~/config
in another console to test the solution.
Notes:
- Symlinks are created for new files/directories, they are removed when targets are removed;
mv
is also covered. - This works well for me even with somewhat troublesome names like
foo bar
ora"b
. - During creation: if there is already an object in
~/
occupying the name then no symlink will be created to overwrite it – no data loss. - During removal: symlinks with proper names are removed no matter where they point to, non-symlinks are left intact thanks to
test -L …
.
Daemon
The iwatch
daemon reads its config file, you can tell it what to do. Not only have I had a problem defining two different actions there but also escaping some characters inside the config file. The easiest solution was to call bash script to do the job.
Before you begin, note:
- Paths should be absolute, modify them to fit your case.
- Also
USERNAME
needs to be modified in the config file and in the script.
This is the snippet to paste into the config file (/etc/iwatch/iwatch.xml
in my OS) just before </config>
:
<watchlist>
<title>symlinks</title>
<contactpoint email="USERNAME@localhost" name="USERNAME"/>
<path type="single" events="create,moved_to,delete,moved_from" alert="off" exec="/home/USERNAME/bin/link_config %e %f">/home/USERNAME/config</path>
</watchlist>
(You may want to remove default watchlist
section, if any.)
Path to the script is /home/USERNAME/bin/link_config
. This is the quick and dirty script:
#!/usr/bin/env bash
p="/home/USERNAME"
e="$1"
f="$(basename "$2")"
case "$e" in
*IN_CREATE|*IN_MOVED_TO)
ln -s "config/$f" "$p/$f"
;;
*IN_DELETE|*IN_MOVED_FROM)
[ -L "$p/$f" ] && rm "$p/$f"
esac
I think if you omit asterisks (*
) and leave bare IN_CREATE
etc. then the script will ignore directories created in /home/USERNAME/config
; maybe this is what you like more. This applies also to command line version.
Make the script executable:
chmod u+x /home/USERNAME/bin/link_config
Set other permissions as you need. The daemon will run it as root
anyway (at least in my OS it was so).
Start/restart/reload the daemon and have fun.