14

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!
else
    # Something went wrong!
    exit 1;
fi

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 '15 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? – James White Apr 25 '15 at 13:37
  • Looks like you found the solution yourself? :-) – Bjorn Munch Apr 25 '15 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 '15 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. – Bjorn Munch Apr 25 '15 at 21:46
12

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
        else
            # No changes were made by rsync
        fi
    else
        # Something went wrong!
        exit 1
    fi

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 '20 at 19:38
2

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?).

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!"
fi

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.