Khi ta định kỳ sync một thư mục local với một thư mục remote, thí dụ Google Drive hay Onedrive, trở ngại lớn nhất là kích thước thư mục. Thời gian kiểm tra để biết file/thư mục nào mới cần tải lên trở nên khá lâu, gần 30 phút với thư mục 100GB và còn tùy ở băng thông upload.
Có một cách khác là giám sát thư mục local, chỉ upload file/thư mục con mới/có thay đổi của nó mà thôi. Việc giám sát này cần inotifywait trong gói inotify-tools.
inotifywait -mr --event 'create,close_write,delete,move' --format "%e %w%f" "$LOCAL_DIR"
Câu lệnh trên cho phép inotify giám sát thư mục $LOCAL_DIR trên các sự kiện create, close_write, delete, move của file và thư mục. Khi có sự kiện này trên thư mục được giám sát, inotifywait báo cho chúng ta tên sự kiện và filename. Tất nhiên khi đó chúng ta lại gọi rclone có hành động tương ứng.
#!/bin/bash
# Script cloudup1, version 20191116
# © 2019 LNT <lnt@ly-le.info>
#
# Cập nhật file/thư mục có thay đổi vào ổ đĩa đám mây
lockfile="/run/$(basename $0).pid"
trap 'sudo rm -f "$lockfile"; rm -rf $SHM' EXIT
echo -e "DATE:$(date)\nPID:$$" | sudo tee "$lockfile" > /dev/null | exit 1
function usage() {
cat >&2 <<EOF
Cập nhật lên ổ đĩa đám mây ->> bỏ qua symlink <<-
usage: $(basename $0) LOCAL_DIR[^LOCAL_DIR2] REMOTE_DIR[^REMOTE_DIR2]
LOCAL_DIR: thư mục được giám sát
EOF
echo -e "[✘] Lỗi: $1!\n"
exit 2
}
SNAME=$(basename $0)
LOG_FILE=/tmp/$SNAME.log
OPT='-u --fast-list --transfers=20 --checkers=20 --tpslimit=20 --drive-chunk-size=1M'
LOG="--log-file=$LOG_FILE"
SHM=$(mktemp -d /dev/shm/$SNAME-XXXX)
[ $# -ne 2 ] && usage "LOCAL_DIR hay REMOTE_DIR không hợp lệ"
LOCAL_DIR="$1"
REMOTE_DIR="$2"
oldIFS=$IFS; IFS='^'; LOCALS=($LOCAL_DIR); REMOTES=($REMOTE_DIR)
printf "%s\n" ${LOCALS[@]} > $SHM/locals; printf "%s\n" ${REMOTES[@]} > $SHM/remotes
# -->> Bỏ # ở 6 dòng sau để test LOCAL_DIR và REMOTE_DIR <<--#
# for local in ${LOCALS[@]}; do
# [ -e $local ] || usage "LOCAL_DIR '$local' không tồn tại"
# done
# for remote in ${REMOTES[@]}; do
# rclone lsd $remote &> /dev/null || usage "REMOTE_DIR '$remote' không xác định"
# done
IFS=$oldIFS
sudo sysctl fs.inotify.max_user_watches=524288 &> /dev/null
sudo sysctl -p &> /dev/null
inotifywait -mr -e CREATE,CLOSE_WRITE,DELETE,MOVED_FROM,MOVED_TO,MOVE_SELF --format "%e %w▁%f" --fromfile $SHM/locals |
while read evt full; do
oIFS=$IFS; IFS="▁"; read wf ef <<< $full; IFS=$oIFS
while read pat; do
[[ "$wf$ef" =~ ^"$pat" ]] && tmp="$wf$ef" && wf="$pat" && ef=${tmp#"$wf"} && break
done < $SHM/locals
file=$wf$ef
dir=${wf##*/}
while read -r remote; do
rfile=${file/"$wf"/"$remote/$dir"}
case $evt in
CLOSE_WRITE,CLOSE)
rclone copyto "$file" "$rfile" $OPT $LOG
;;
CREATE,ISDIR)
[ -z "$(ls -A "$file")" ] && rclone mkdir "$rfile" || rclone copyto "$file" "$rfile" $OPT $LOG
;;
MOVED_FROM,ISDIR)
echo "$rfile" > $SHM/$remote
;;
MOVED_FROM)
echo "$rfile" > $SHM/$remote
(
sleep .2
afile=$(<$SHM/$remote) && >$SHM/$remote
[ -d $afile ] && cmd=purge || cmd=delete
[ ! -z "$afile" ] && rclone $cmd "$afile" $OPT $LOG &> /dev/null
) &
;;
MOVED_TO|MOVED_TO,ISDIR)
ofile=$(<$SHM/$remote) && >$SHM/$remote
[ -z "$ofile" ] && rclone copyto "$file" "$rfile" $OPT $LOG || rclone moveto "$ofile" "$rfile" $OPT $LOG
;;
MOVE_SELF) #folder only
ofile=$(<$SHM/$remote) && >$SHM/$remote
[ -z "$ofile" ] || rclone purge "$rfile" $LOG
;;
esac
done < ${SHM}/remotes
done
Script cloudup1 được gọi thường trú mỗi khi RPi khởi động
@reboot /path/to/cloudup1 local_folder remote:folder
Script cloudup1 trên chấp nhận nhiều LOCAL_DIR và nhiều REMOTE_DIR, chấp nhận tên file có khoảng trắng.
Gỉa sử ta muốn backup tức thời các file/thư mục thuộc /home/pi/Documents và /mnt/task vào các ổ đĩa đám mây:
cloudup1 /home/pi/Documents^/mnt/task gdrive:office^onedrive:office
Các file thuộc Documents sẽ backup ở office/Documents, task ở office/task
Script này bỏ qua các symlink (xem như không có)
Chú thích
- Rclone hỗ trợ symbolic link nhưng inotifywait thì không. File trong thư mục đích của symlink có thay đổi nhưng symlink vẫn không thay đổi nên inotifywait không phát hiện, do vậy script không cập nhật lên REMOTE_DIR.
- Tuy nhiên, script có thể được cải tiến để hỗ trợ symlink bằng cách giám sát cả thư mục đích của mọi symlink trong thư mục local (đã xong!)
- Script dùng cho các ổ đĩa đám mây được rclone hỗ trợ.