Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Is there a way to have cp's --update option print files that did not copy because the source directory contained a newer version of the file?

share|improve this question

migrated from stackoverflow.com Apr 16 '12 at 14:49

This question came from our site for professional and enthusiast programmers.

There is no 'bash cp command'. There is a Unix/Linux cp command, and you might invoke it from bash .. or zsh .. or ksh .. or sh ..... – bmargulies Apr 15 '12 at 2:06
I don't think so, but the -v option will tell you when files DID copy. Perhaps you can figure out the ones that didn't from that? – Tim Pote Apr 15 '12 at 2:08
@bmargulies Although you're correct, that's kind of a pedantic distinction. He obviously meant invoking the cp command from the bash shell. – Tim Pote Apr 15 '12 at 2:11

Replace cp -ur with rsync -urvv.

The two "v"-s there are not a typo: they are there for increased verbosity, to show the files that were skipped.

The skipped files will look like the_filename is newer, so to get the list of skipped files you can use this one-liner:

rsync -urvv source/ target | grep ' is newer$' | sed -e 's/ is newer$//'

Or if you will be using it interactively the --progress flag can be very useful.

share|improve this answer
This is much better than my posted solution. +1 for remembering rsync. – Tim Pote Apr 22 '12 at 14:24

I don't think there is a way to have cp do that directly, but this should do essentially the same thing:

cp -vu file destination | awk '{ gsub("[`\x27]", "", $1); print $1 } END { if (NR == 0) print "NOFILES" }' | xargs -I{} find . ! -name {} -maxdepth 1

This little one-liner comes with some limitations:

1) It depends on there not being any files named "NOFILES". You can change that string in the awk command to suite your needs.

2) You must be in the directory where file exists. If you are not in that directory, you need to change the find command to be find dirWhereFileExists instead of find . If you aren't copying from a single directory you can use find dir1 dir2... instead.

3) It won't work if you for some reason have backticks or single quotes in your filenames.

As you can tell this isn't the most robust solution, but it should do for a one-off operation.


I woke up this morning and realized that the above solution was garbage. If you tried to copy multiple files it would search as many times as you have files, excluding one file each time. The following solution, however, should work:

cp -vu file destination | awk '{ gsub("[`\x27]", "", $1); regex = $1 "|" regex } END { if (NR == 0) { regex = "NOFILES|" } print ".*/("substr(regex, 0, length(regex))")" }' | xargs -I{} find . -regextype posix-extended ! -regex {} -maxdepth 1

It builds up a regex as it goes and passes that to find instead. Same limitations as above apply.

Sorry about the brain-fart earlier. Guess it was too late to be on StackOverflow.

share|improve this answer

Would rsync do the job for you? It has many options that fit your description, say "don't overwrite newer files" and such. And you can have it log findings. I use it often for remote AND local file copying.

You can get very granular with it too.

Good luck.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.