#!/bin/csh -f # cpmod_via_rsync # ----------------------------------------------------------------------------- # Shell script to copy all modified files from the specified source directory # tree to the specified target directory tree. Modified means that the file # is different from the corresponding file in the optional specified reference # directory tree. Useful for doing incremental backups, by specifying the # most recent full backup as the reference directory. If no reference # directory is specified, all files are assumed to be modified. # ----------------------------------------------------------------------------- # Usage: See Usage section below or run with no arguments to see usage. # Assumptions: # Effects: # - Copies files # Notes: # - Like rsync --compare-dest, but does not leave behind a bunch of empty # subdirectories in the target tree. It explicitly deletes them at the end. # Implementation Notes: # Portability Issues: # Revision History: # $Log$ # ------------------------------------------------------------------------------ # Get and check params set show_usage = false if ($#argv < 2) then beep "At least 2 arguments are required." set show_usage = true else set source_dir = "$1" if (! -d "$source_dir") then beep "source_dir $source_dir must be an existing directory." set show_usage = true else set target_dir = "$2" if (! -d "$target_dir") then beep "target_dir $target_dir must be an existing directory." set show_usage = true else set ref_dir = "$3" if ("$ref_dir" == "") then set compare_dest_option = "" else set compare_dest_option = "--compare-dest=$ref_dir" set firstchar = "`echo $ref_dir:q | cut -c 1`" if ("$firstchar" == "/" || "$firstchar" == "~") then if (! -d "${ref_dir}") then beep "ref_dir $ref_dir must be an existing directory." set show_usage = true endif else if (! -d "${target_dir}/${ref_dir}") then echo "ref_dir $ref_dir must be an existing directory" echo "relative to target_dir $target_dir." beep "That is, ${target_dir}/${ref_dir} must exist." set show_usage = true endif endif endif endif endif endif # Report usage errors if ($show_usage == true) then echo "Usage: $0:t source_dir target_dir [ref_dir]" echo "Copies all files from source_dir tree to target_dir tree that do not" echo "exactly match the corresponding file in ref_dir tree. Match means" echo "that the contents, date/time, owner, etc. all match exactly." echo "If no ref_dir is specified, all files are copied." echo "Note: If ref_dir is a relative directory, it is treated as relative" echo " to dest_dir, not relative to the current working directory." exit 1 endif # Copy the files, stripping lines ending in slash from the output sent # to the screen to avoid cluttering the report with names of directories # copied. Only interested in names of files. rsyncupdate --log --del $compare_dest_option ${source_dir}/ $target_dir | grep -v -e '/$' set rc = $status # Problem: The pipe to grep causes $status to be the status of grep, not # of rsyncupdate. Bash can get around this via $PIPESTATUS, but # no such technique in csh or tcsh. # - May have to re-write this as a bash script. # - Or remove the -v option from rsyncupdate, and list the names # of the resulting files after deleting the empty subdirectories # below. # - Or avoid the pipe by writing output to a temp file, grepping # it, then deleting it. # - For now, live with the wrong status, and just watch the output # for errors reported by rsyncupdate # - Best solution: See new version of quick, which uses # rsync --backup instead of rsync --compare-dest. No more need # for cpmod at all. # Delete the potentially many empty subdirectories created in target_dir. # Couldn't find a way to get rsync to not create the entire empty tree. # Here's why the rsync option --prune-empty-dirs doesn't help: # http://lists.samba.org/archive/rsync/2010-March/024787.html # http://lists.samba.org/archive/rsync/2009-April/023108.html # http://lists.samba.org/archive/rsync/2009-April/023112.html # http://lists.samba.org/archive/rsync/2009-April/023116.html find $target_dir -depth -type d -empty -delete if ($rc != 0) then echo "" endif exit $rc