Skip to content

Instantly share code, notes, and snippets.

@leucos
Last active March 9, 2022 21:56
Show Gist options
  • Save leucos/d3d8b2686ba8ab46c64a6f01d3ef9f53 to your computer and use it in GitHub Desktop.
Save leucos/d3d8b2686ba8ab46c64a6f01d3ef9f53 to your computer and use it in GitHub Desktop.
This program moves files form one machine to another
#!/bin/bash
set -eu
#
# This program watches new files and moves them from one machine to another
#
# How it works
#
# mover.sh will recursively watch changes in a directory using inotifywait.
# When the file is closed (after a write), the file is rsynced to the
# destination directory and removed from the local filesystem.
#
# If a directory is created, inotifywait will be restarted so it creates
# watches in the newly created directories.
#
# Since files can be created in a new depp directory hierarchy, we make use of
# rsync's -R flag and 'dotted' path (hence the requirement for rsync 2.6.7).
#
# For instance, if you run:
#
# mover.sh /tmp/a/ /tmp/b/ user@host
#
# and create a file 'foo' in /tmp/a/x/y/z/, hierarchy '/tmp/b/x/y/z/' might not
# exist on the remote system.
#
# This script takes care of this using the aformentioned options, and will
# execute:
#
# rsync -Ravz --remove-source-files /tmp/a/./x/y/z/foo leucos@devops.works:/tmp/b/
#
# which will take care of 'mkdir -p /tmp/b/x/y/z' before syncing foo.
#
usage() {
echo -e "Usage: $0 <SRC> <DST> [REMOTE]\n"
echo -e "\tSRC: absolute path of source to check"
echo -e "\tDST: absolute path of destination to copy to (on the remote if specified)"
echo -e "\tREMOTE: remote machine to copy to (in ssh form, e.g. user@host.machine)"
}
move() {
local src=$1
local dst=$2
local remote=$3
# if we have a remote, prefix dst with it
if [ -n "$remote" ]; then
dst="$remote:$dst"
fi
# -R makes use of relative paths
echo rsync -Ravz --remove-source-files $src $dst
# Uncomment for real action
# rsync -Ravz --remove-source-files $src $dst
}
monitor() {
local src=$1
local dst=$2
local remote=$3
while read res; do
op=$(echo "$res" | cut -f1 -d' ')
dir=$(echo "$res" | cut -f2 -d' ')
file=$(echo "$res" | cut -f3 -d' ')
pruned=${dir#${src}}
echo "$res (pruned: ${pruned})"
case $op in
*ISDIR)
echo "directory ${dir} created"
break
;;
CLOSE_WRITE*)
echo "$op TRIGGERS => move ${src}./${pruned}${file} ${dst} ${remote}"
move "${src}./${pruned}${file}" "${dst}" "${remote}"
;;
*)
echo "nothing to do for $op"
esac
done < <(inotifywait -r -m --format '%:e %w %f' -e create,close_write "$src")
}
source=$1
destination=$2
remote=${3:-}
if [ ! -r "$source" ]; then
echo "ERROR: source $source does not exist"
exit 1
fi
if [[ "$source" != /* ]]; then
echo "ERROR: source $source path must be absolute"
exit 1
fi
if [ ! -r "$destination" ]; then
echo "ERROR: destination $destination does not exist"
exit 1
fi
if [[ "$destination" != /* ]]; then
echo "ERROR: destination $destination path must be absolute"
exit 1
fi
if [ ! -r "$remote" ]; then
echo "WARNING: no remote specified; will work locally"
fi
while true; do
monitor "$source" "$destination" "$remote"
echo "Directory created, respawning"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment