I have a script which uses rsync to sync data in a remote -> local scenario. Immediately after the rsync command is run, a check to see if the error code equals zero or not. If its zero, further commands are performed. This however doesn't take into account the fact that rsync might have ran successfully but not actually made any changes. Because of this the equal zero condition will run regardless, which is a little redundant.

rsync -aEivm --delete /path/to/remote/ /path/to/local/

if [ $? -eq 0 ]; then
    # Success do some more work!
    # Something went wrong!
    exit 1;

What would be the best approach to expand this to check if there were actually any changes based on the rsync command that ran. I've read that -i flag can provide output to stdout, but how can this be placed in a conditional block?

  • You've got -v in there, so it is already providing the information you need to stdout...e.g., a list of files that were actually sent. If nothing is changed, that's just ./.
    – goldilocks
    Apr 25, 2015 at 13:35
  • Ah! What if I took out -v and use -i instead and then use a non-empty string check on the rsync command? Apr 25, 2015 at 13:37
  • Looks like you found the solution yourself? :-) Apr 25, 2015 at 13:50
  • 2
    you can use a=$("rsync command"). This would execute the rsync command and store stdout in a. Then you can run tests on a
    – nitishch
    Apr 25, 2015 at 18:42
  • 1
    You could also add a | grep / or something like that, then check the exit status of grep with $?, it should be 1 if there was no output. Apr 25, 2015 at 21:46

2 Answers 2


Based on the comments to my original question, make rsync output to stdout with the -i flag and use a non string check condition to see if anything actually changed within the error code check. Wrapping the rsync command in a variable allows the check to be done.

RSYNC_COMMAND=$(rsync -aEim --delete /path/to/remote/ /path/to/local/)

    if [ $? -eq 0 ]; then
        # Success do some more work!

        if [ -n "${RSYNC_COMMAND}" ]; then
            # Stuff to run, because rsync has changes
            # No changes were made by rsync
        # Something went wrong!
        exit 1

Potential downside, you have to lose the verbose output, but you can always log it to a file instead.

  • I'm not sure why you've added options -Em (maybe for some custom need of yours?). Otherwise it worked for me.
    – ndemou
    Jun 21, 2020 at 19:38

I wanted a more strict solution. I don't want to grep for Number of created files: (the message could be in another language) or remove all lines but two in -v output (who knows what summary rsync will print in the next version?).

edit: I found that you can set the format of a rsync's output to list the changed files with --out-format:

rsync -a --verbose source-dir target-dir \
     --out-format='changed file: %i %n%L' \
  | fgrep 'changed file:'

Or, if you don't care about file times but want to do minimal copying, a variant with expanded and cleaned up -a:

rsync -r --links --devices --specials \
      --delete --checksum \
      --omit-dir-times --omit-link-times --ignore-times \
      --prune-empty-dirs \
      --verbose \
    source-dir target-dir

Old answer: I found that you can set the format of a rsync's log, but not the format of its stdout (see man rsyncd.conf).

For example, add a "File changed!" to each line with an actually changed file, and then grep for it:

rsync -a \
    --log-file=/tmp/rsync.log \
    --log-file-format="File changed! %f %i" \
    source-dir target-dir

if fgrep "File changed!" /tmp/rsync.log > /dev/null; then
    echo "rsync did something!"
  • 1
    I tried this and couldn't get it to work until I realized that it was appending to the log file, so once rsync did something, the script continued to think it did something even when it didn't, until the log was removed. I resolved this easily by removing /tmp/rsync.log (if it existed) at the start of the script. Sep 17, 2021 at 17:59

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .