#!/bin/csh -f # cpmod # ------------------------------------------------------------------------------ # 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 newer than the specified timestamp file in the specified source directory. # Optionally updates the timestamp of the timestamp file after the copy # completes successfully. If the timestamp file doesn't exist, prompts the user # and creates it. Creates nested target directories as needed. # ------------------------------------------------------------------------------ # Usage: See Usage section below or run with no arguments to see usage. # Assumptions: # Effects: # - Copies files and creates/updates timestamp file. # Notes: # Implementation Notes: # - Timestamp is updated after the copy finishes. There's a race condition # here -- other files may be created after the copy begins and before the # timestamp is updated. May be missed by this copy and skipped by future # copies. Beware running while files in the source tree are being added # and modified. # Portability Issues: # Revision History: # $Log$ # ------------------------------------------------------------------------------ # Check for option to confirm files to be copied and free disk space before # copying. # ?? Change this to not be required to be the first option, by using a # ?? loop to loop through the options. set option_confirm = false if ("$1" == "-i") then set option_confirm = true shift endif # Get and check options set show_usage = false set option_update = false if ("$1" == "-u" && "$2" != "") then set option_update = true set timestamp = $2:q shift shift else if ("$1" == "-n" && "$2" != "") then set option_update = false set timestamp = $2:q shift shift else echo "Must explicitly specify either -u or -n, and a timestamp filename." set show_usage = true endif # Get and check source_dir and target_dir params if ($show_usage != true) then if ($#argv < 2) then echo "At least 2 arguments are required." set show_usage = true else set source_dir = "$1" if (! -d "$source_dir") then echo "source_dir $source_dir must be an existing directory." set show_usage = true else set timestamp = "$source_dir/$timestamp" set target_dir = "$2" if (! -d "$target_dir") then echo "target_dir $target_dir must be an existing directory." set show_usage = true endif endif endif endif # Report usage errors if ($show_usage == true) then echo "Usage: $0:t [-i] [[-u | -n] timestamp_filename] source_dir target_dir" echo "Options:" echo " -i = Show files, sizes, and free space and" echo " prompt to confirm" echo " -u timestamp_filename = Update timestamp after copying files." echo " -n timestamp_filename = Do not update timestamp after copying." echo "Must specify either -u or -n, and a timestamp filename." echo "Timestamp filename must be specified relative to source_dir." exit 1 endif # Move to $source_dir so find will operate on it via its "." param and will # find $timestamp there, and to keep the filenames as short as possible. # Note: Could avoid this by using $source_dir instead of "." and # $source_dir/$timestamp instead of $timestamp on the find command, # but that would make the names echoed to the user unnecessarily # longer, and would also generate longer names for find to pass to # xargs and for xargs to batch up for the commands it calls. cd "$source_dir" # Copy the files set rc = 0 if (-e "$timestamp") then # Show files, sizes, and free space, and prompt the user to confirm if ($option_confirm == true) then echo "Files to be copied:" find -s . -not -type d -newer "$timestamp" -print0 | xargs -0 du -ck | more echo "Free space on $target_dir" df -k $target_dir echo -n "Copy files (y/n)? " set copyfiles=$< if ("$copyfiles" != "y") then exit 1 endif endif find -s . -newer "$timestamp" -print0 | xargs -0 -n 1 -J % xargsabort cprelsafe % "$target_dir" # -s = Sort filenames within each directory so they are copied in # an order that makes sense to the user. Strictly cosmetic. # . = Start in current working directory # -newer = Only files newer than the timestamp # -print0 = Generate filenames separated by nulls not whitespace # xargs = Pass filenames from find to command line of xargsabort # -0 = Expect filenames separated by nulls not whitespace # -t = Echo xargsabort commands (off generally, for debug only) # -n 1 = Pass one file at a time to xargsabort # -J % = Insert filename into xargsabort command at % sign # xargsabort = Do the cprelsafe command, abort xargs if any error occurs. # cprelsafe = Copy one file suppressing error if it's a directory. # % = Insert filename into xargsabort command here # $target_dir = 2nd param to cprelsafe, target directory for copy set rc = $status else echo "Timestamp file not found: $timestamp" echo -n "Copy all files (y/n)? " set copyall=$< if ("$copyall" == "y") then # Show files, sizes, and free space, and prompt the user to confirm if ($option_confirm == true) then echo "Files to be copied:" du -ck | more echo "Free space on $target_dir" df -k $target_dir echo -n "Copy files (y/n)? " set copyfiles=$< if ("$copyfiles" != "y") then exit 1 endif endif cp -v -R ./ "$target_dir" set rc = $status endif endif # Update the timestamp if successful and requested. if ($option_update == true) then if ($rc == 0) then touch "$timestamp" else echo "Error $rc occurred during copy. $timestamp not updated." endif endif if ($rc != 0) then echo "" endif exit $rc