Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

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.

share|improve this question

2 Answers 2

up vote 1 down vote accepted

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.

target=/path/to/destination
cd source-directory
skip=
err=0
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
    skip=$x
    if [[ -e $target/$x ]]; then
      echo 1>&2 "Not overwriting non-directory $target/$x with a directory."
      err=1
    else
      # The directory doesn't exist on the destination, so copy it
      cp -Rp -- "$x" "$target/$x" || err=1
    fi
  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
    fi
  else
    # neither a file nor a directory. Overwrite the destination
    cp -p -- "$x" "$target/$x" || err=1
  fi
done
share|improve this answer
    
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...

share|improve this answer
    
“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

 
discard

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

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