Last active
April 10, 2025 09:00
-
-
Save affix/370b6b7abc6caff21d82b75186b3b362 to your computer and use it in GitHub Desktop.
A Bash script to do rclone bisync, I use this to sync proton drive on Linux but you can use it for anything rclone supports, This creates a systemd service to manage the sync process, You user must support linger enable with `sudo loginctl enable-linger $USER`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# RCLONE_SYNC_PATH: The path to COPY FROM (files are not synced TO here): | |
RCLONE_SYNC_PATH="/home/${USER}/rclonedrive" | |
# RCLONE_BACKUP_PATH: Backup Directory | |
RCLONE_BACKUP_PATH="/backup/rclone" | |
# RCLONE_REMOTE: The rclone remote name to synchronize with. | |
RCLONE_REMOTE="remote:" | |
# RCLONE_CMD: The sync command and arguments: | |
RCLONE_CMD="rclone bisync ${RCLONE_SYNC_PATH} ${RCLONE_REMOTE} --force --backup-dir1 ${RCLONE_BACKUP_PATH} --verbose --recover" | |
# WATCH_EVENTS: The file events that inotifywait should watch for: | |
WATCH_EVENTS="modify,delete,create,move" | |
# SYNC_DELAY: Wait this many seconds after an event, before synchronizing: | |
SYNC_DELAY=5 | |
# SYNC_INTERVAL: Wait this many seconds between forced synchronizations: | |
SYNC_INTERVAL=3600 | |
# NOTIFY_ENABLE: Enable Desktop notifications | |
NOTIFY_ENABLE=true | |
# SYNC_SCRIPT: dynamic reference to the current script path | |
SYNC_SCRIPT=$(realpath $0) | |
notify() { | |
MESSAGE=$1 | |
if test ${NOTIFY_ENABLE} = "true"; then | |
notify-send "rclone ${RCLONE_REMOTE}" "${MESSAGE}" | |
fi | |
} | |
# Copy a single file to remote | |
sync_single_file() { | |
local FILE_PATH="$1" | |
# Skip directories | |
if [[ -d "$FILE_PATH" ]]; then return; fi | |
# Get relative path from RCLONE_SYNC_PATH | |
REL_PATH="${FILE_PATH#$RCLONE_SYNC_PATH/}" | |
# Parent directory of the destination (in case it doesn't exist) | |
DEST_DIR=$(dirname "${RCLONE_REMOTE}${REL_PATH}") | |
echo "Uploading file: $REL_PATH" | |
# rclone copyto preserves destination filename, avoids directory auto-creation | |
rclone copyto "$FILE_PATH" "${RCLONE_REMOTE}${REL_PATH}" && \ | |
notify "Copied: $REL_PATH" | |
} | |
rclone_sync() { | |
set -x | |
# Do initial sync immediately: | |
notify "Started rclone sync service" | |
${RCLONE_CMD} | |
# Watch for file events and do continuous immediate syncing | |
# and regular interval syncing: | |
while [[ true ]] ; do | |
EVENT=$(inotifywait --recursive --timeout ${SYNC_INTERVAL} -e ${WATCH_EVENTS} \ | |
--format '%e %w%f' "${RCLONE_SYNC_PATH}" 2>/dev/null) | |
INOTIFY_EXIT=$? | |
if [ $INOTIFY_EXIT -eq 0 ]; then | |
EVENT_TYPE=$(echo "$EVENT" | awk '{print $1}') | |
FILE_PATH=$(echo "$EVENT" | cut -d' ' -f2-) | |
echo "Detected event: $EVENT_TYPE on $FILE_PATH" | |
sleep ${SYNC_DELAY} | |
case "$EVENT_TYPE" in | |
MODIFY|CREATE|CLOSE_WRITE|MOVED_TO) | |
sync_single_file "$FILE_PATH" | |
;; | |
DELETE|MOVED_FROM) | |
REL_PATH="${FILE_PATH#$RCLONE_SYNC_PATH/}" | |
echo "Deleting remote: ${REL_PATH}" | |
rclone deletefile "${RCLONE_REMOTE}${REL_PATH}" && \ | |
notify "Deleted: $REL_PATH" | |
;; | |
*) | |
echo "Unhandled event: $EVENT_TYPE" | |
;; | |
esac | |
elif [ $? -eq 2 ]; then | |
# Do the sync now even though no changes were detected: | |
${RCLONE_CMD} | |
fi | |
done | |
} | |
systemd_setup() { | |
set -x | |
mkdir -p ${HOME}/.config/systemd/user | |
SERVICE_FILE=${HOME}/.config/systemd/user/rclone_sync.${RCLONE_REMOTE}.service | |
if test -f ${SERVICE_FILE}; then | |
echo "Unit file already exists: ${SERVICE_FILE} - Not overwriting." | |
else | |
cat <<EOF > ${SERVICE_FILE} | |
[Unit] | |
Description=rclone_sync ${RCLONE_REMOTE} | |
[Service] | |
ExecStart=${SYNC_SCRIPT} | |
[Install] | |
WantedBy=default.target | |
EOF | |
fi | |
systemctl --user daemon-reload | |
systemctl --user enable --now rclone_sync.${RCLONE_REMOTE} | |
systemctl --user status rclone_sync.${RCLONE_REMOTE} | |
echo "You can watch the logs with this command:" | |
echo " journalctl --user --unit rclone_sync.${RCLONE_REMOTE}" | |
} | |
if test $# = 0; then | |
rclone_sync | |
else | |
CMD=$1; shift; | |
${CMD} $@ | |
fi | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment