E.g., if you want to merge two directories with each other (by moving everything from directory 1 into directory 2), and both directory 1 and directory 2 have some files with the same name.

Then how can you write code such that if SharedFile is found in both directories, then replace SharedFile in directory 2 with SharedFile in directory 1 IF SharedFile is bigger in directory 1 and SharedFile has a later modification date in directory 1? (but do not replace SharedFile otherwise).

I'm fine with both tcsh and bash scripts.


Here's a bash/ksh93/zsh script that emulates the core behavior of rsync, where you can easily tune the decision to copy or not copy a source file. Here a copy is made only if the source file is both larger and newer. In bash, add shopt -s globdots before the script. Untested.

cd source-directory
for x in **/*; do
  # Skip the contents of a directory that has been copied wholesale
  case $x in $skip/*) continue;; *) skip=;; esac
  if [[ -d $x ]]; then
    # Recreate source directory on the target.
    # Note that existing directories do not have their permissions or modification times updated.
    if [[ -e $target/$x ]]; then continue; fi
    if [[ -e $target/$x ]]; then
      echo 1>&2 "Not overwriting non-directory $target/$x with a directory."
      # The directory doesn't exist on the destination, so copy it
      cp -Rp -- "$x" "$target/$x" || err=1
  elif [[ -f $x ]]; then
    # We have a regular file. Copy it over if desired.
    if [[ $x -nt $target/$x ]] && [ $(wc -c <"$x") -gt $(wc -c <"$target/$x") ]; then
      cp -p -- "$x" "$target/$" || err=1
    # neither a file nor a directory. Overwrite the destination
    cp -p -- "$x" "$target/$x" || err=1
  • As long as that works as advertised, it is a more precise solution than mine, but a little more complicated in implementation (but not much, I admit). Personally, I'm a little lazy, and the rsync tool is so friggin' versatile that I probably end up using it instead of cp, mv, scp, diff, and some other things even more than is healthy. – killermist Jun 23 '12 at 3:03
  • @killermist I don't see a solution from you. Your answer ignores one of the requirements. – Gilles Jun 23 '12 at 7:55

According to rsync --help:

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

So, the command you're probably looking for is:

rsync -auPsourcedir/ destdir/

Then delete sourcedir after the fact.

Of course, remember the significance of trailing /'s in rsync.

I don't know that there is an rsync behavior for treating larger files as better...

  • “I don't know that there is an rsync behavior for treating larger files as better...” Neither do I. So this doesn't really answer the question. – Gilles Jun 23 '12 at 7:54

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.