30

I'm doing this sync locally on Ubuntu 12.04. The files are generally small text files (code).

I want to copy (preserving mtime stamp) from source directory to target but I only want to copy if the file in target already exists and is older than the one in source.

So I am only copying files that are newer in source, but they must exist in target or they won't be copied. (source will have many more files than target.)

I will actually be copying from source to multiple target directories. I mention this in case it impacts the choice of solution. However, I can easily run my command multiple times, specifying the new target each time, if that's what is required.

1 Answer 1

44

I believe you can use rsync to do this. The key observation would be in needing to use the --existing and --update switches.

 --existing skip creating new files on receiver -u, --update skip files that are newer on the receiver 

A command like this would do it:

$ rsync -avz --update --existing src/ dst 

Example

Say we have the following sample data.

$ mkdir -p src/; touch src/file{1..3} $ mkdir -p dst/; touch dst/file{2..3} $ touch -d 20120101 src/file2 

Which looks as follows:

$ ls -l src/ dst/ dst/: total 0 -rw-rw-r--. 1 saml saml 0 Feb 27 01:00 file2 -rw-rw-r--. 1 saml saml 0 Feb 27 01:00 file3 src/: total 0 -rw-rw-r--. 1 saml saml 0 Feb 27 01:00 file1 -rw-rw-r--. 1 saml saml 0 Jan 1 2012 file2 -rw-rw-r--. 1 saml saml 0 Feb 27 01:00 file3 

Now if I were to sync these directories nothing would happen:

$ rsync -avz --update --existing src/ dst sending incremental file list sent 12 bytes received 31 bytes 406.00 bytes/sec total size is 0 speedup is 0.00 

If we touch a source file so that it's newer:

$ touch src/file3 $ ls -l src/file3 -rw-rw-r--. 1 saml saml 0 Feb 27 01:04 src/file3 

Another run of the rsync command:

$ rsync -avz --update --existing src/ dst sending incremental file list file3 sent 115 bytes received 31 bytes 292.00 bytes/sec total size is 0 speedup is 0.00 

We can see that file3, since it's newer, and that it exists in dst/, it gets sent.

Testing

To make sure things work before you cut the command loose, I'd suggest using another of rsync's switches, --dry-run. Let's add another -v too so rsync's output is more verbose.

$ rsync -avvz --dry-run --update --existing src/ dst sending incremental file list delta-transmission disabled for local transfer or --whole-file file1 file2 is uptodate file3 is newer total: matches=0 hash_hits=0 false_alarms=0 data=0 sent 88 bytes received 21 bytes 218.00 bytes/sec total size is 0 speedup is 0.00 (DRY RUN) 
4
  • Thank you. Don't I need a few more rsync options? I'm reading the man page. Seems like I might need this: rsync --archive --update --existing --whole-file --itemize-changes a/ b. Or are most of those options unnecessary? (I added whole file because these are mostly small text files.) Commented Feb 27, 2014 at 6:14
  • @MountainX - only add options you need. I'd start with -a that's a superset of switches, -rlptgoD. Commented Feb 27, 2014 at 6:17
  • Let me clarify that. I'm confused about --update and --existing. Do I need both? I tested your solution and it seems to work, but I still feel safer adding --update . Commented Feb 27, 2014 at 6:20
  • @MountainX - sure you can add it in, I'll put it in the A too. Commented Feb 27, 2014 at 6:24

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.