make rsync wait for a confirmation before actually changing files

Solution 1:

In lieu of an official "--confirm" option, rsync's own "batch mode" can be leveraged to bypass having to twice compute the difference between two paths. Batch mode was intended for distributing changes to mirrors (compute once, update many identical trees). Two files are created: a batch file containing the updates and a simple convenience script for running the update (there's a section toward the end of the rsync man page with details).

Here's a bash wrapper for abstracting the process:

#!/bin/bash

cleanup ()
{
    rm ${BFILE} ${BFILE}.sh &>/dev/null
}

# generate tmpfile
BFILE=$( mktemp )

# rsync command
if ! rsync --only-write-batch="${BFILE}" --verbose "$@"; then
    cleanup
    exit 1
fi

# confirmation
read -p "Continue (y/N)? " confirm
if [ "$confirm" != "y" ]; then
    echo "Aborting"
    cleanup
    exit 1
fi

# carve up arguments
dest="${@: -1}"         # last argument
host="${dest%%:*}"      # host:path
path="${dest#*:}"
opts="${@:1:$(($#-2))}" # everything but the last two args
if [ "$host" = "${path}" ]; then
    # local
    sh "${BFILE}.sh"
else
    # remote
    ssh "$host" rsync --read-batch=- "${opts}" "${path}" <"${BFILE}"
fi

cleanup

Note that since this script writes to $TMP_DIR, you might run into space constraints if you are moving really big data (larger than your /tmp, for instance).

Solution 2:

You can use the -n option with rsync to perform a dry run. rsync will tell you what operations it would have performed without actually doing them. If you're happy with the results, re-run without the -n option.

Solution 3:

You may make rsync to backup files on overwrite, using --backup option,

 -b, --backup                make backups (see --suffix & --backup-dir)
     --backup-dir=DIR        make backups into hierarchy based in DIR
     --suffix=SUFFIX         backup suffix (default ~ w/o --backup-dir)

after rsync run you can scan backup-dir for files and ask one by one if it need to be restored.

Solution 4:

Sadly, there is no built in method in Rsync at the time writing.

Mike Fitzpatrick's solution will work fine, however if you have a very large directory tree, you may want to do something that doesn't make rsync go through all the files again

EDIT: There is also a bug where it wont delete a destination file... the more and more I look at it, this solution is broken... I am leaving it up becase it may work in your case and also if someone wants to fix it. Also, someone should submit a formal feature request to https://bugzilla.samba.org/enter_bug.cgi?product=rsync

I wrote this script:

#! /bin/bash

# Make a temp file for storing the output of rsync

tmpfile=$( mktemp )  &&

# Do all the hard work ( get the list of files we need to update ), 
#  but dont actually change the filesystem

rsync --dry-run --out-format='RSYNC_CONFIRM %i %n%L' "$@" | grep RSYNC_CONFIRM | awk '{ print $3 }' > $tmpfile &&


# Output to the user what we propose to do
rsync --dry-run --itemize-changes --files-from=$tmpfile "$@" &&

# Alternatively, we could just output $tmpfile... but whatever...

read -p "Continue? (y/n)?" &&

if [[ $REPLY = [yY] ]]
then
{
  rsync --files-from=$tmpfile "$@"
}
fi

rm $tmpfile
  • Try pasting the script into a file called rsync-confirm.bash

  • Then chmod +x rsync-confirm.bash

  • Then ./rsync-confirm.bash -rvh /etc/ /tmp/etc/

This script might be a little buggy, I noticed that it doesn't really like it if you don't have a trailing slash on the source directory...