Shall高级编程

源代码在线查看: nightly-backup.sh

软件大小: 1353 K
上传用户: stuoju
关键词: Shall 高级编程
下载地址: 免注册下载 普通下载 VIP

相关代码

				#!/bin/bash				# nightly-backup.sh				# http://www.richardneill.org/source.php#nightly-backup-rsync				# Copyright (c) 2005 Richard Neill <backup@richardneill.org>.				# This is Free Software licensed under the GNU GPL.				# ==> Included in ABS Guide with script author's kind permission.				# ==> (Thanks!)								#  This does a backup from the host computer to a locally connected				#+ firewire HDD using rsync and ssh.				#  It then rotates the backups.				#  Run it via cron every night at 5am.				#  This only backs up the home directory.				#  If ownerships (other than the user's) should be preserved,				#+ then run the rsync process as root (and re-instate the -o).				#  We save every day for 7 days, then every week for 4 weeks,				#+ then every month for 3 months.								#  See: http://www.mikerubel.org/computers/rsync_snapshots/				#+ for more explanation of the theory.				#  Save as: $HOME/bin/nightly-backup_firewire-hdd.sh								#  Known bugs:				#  ----------				#  i)  Ideally, we want to exclude ~/.tmp and the browser caches.								#  ii) If the user is sitting at the computer at 5am,				#+     and files are modified while the rsync is occurring,				#+     then the BACKUP_JUSTINCASE branch gets triggered.				#      To some extent, this is a 				#+     feature, but it also causes a "disk-space leak".																								##### BEGIN CONFIGURATION SECTION ############################################				LOCAL_USER=rjn                # User whose home directory should be backed up.				MOUNT_POINT=/backup           # Mountpoint of backup drive.				                              # NO trailing slash!				                              # This must be unique (eg using a udev symlink)				SOURCE_DIR=/home/$LOCAL_USER  # NO trailing slash - it DOES matter to rsync.				BACKUP_DEST_DIR=$MOUNT_POINT/backup/`hostname -s`.${LOCAL_USER}.nightly_backup				DRY_RUN=false                 #If true, invoke rsync with -n, to do a dry run.				                              # Comment out or set to false for normal use.				VERBOSE=false                 # If true, make rsync verbose.				                              # Comment out or set to false otherwise.				COMPRESS=false                # If true, compress.				                              # Good for internet, bad on LAN.				                              # Comment out or set to false otherwise.								### Exit Codes ###				E_VARS_NOT_SET=64				E_COMMANDLINE=65				E_MOUNT_FAIL=70				E_NOSOURCEDIR=71				E_UNMOUNTED=72				E_BACKUP=73				##### END CONFIGURATION SECTION ##############################################												# Check that all the important variables have been set:				if [ -z "$LOCAL_USER" ] ||				   [ -z "$SOURCE_DIR" ] ||				   [ -z "$MOUNT_POINT" ]  ||				   [ -z "$BACKUP_DEST_DIR" ]				then				   echo 'One of the variables is not set! Edit the file: $0. BACKUP FAILED.'				   exit $E_VARS_NOT_SET				fi								if [ "$#" != 0 ]  # If command-line param(s) . . .				then              # Here document(ation).				  cat 				    Automatic Nightly backup run from cron.				    Read the source for more details: $0				    The backup directory is $BACKUP_DEST_DIR .				    It will be created if necessary; initialisation is no longer required.								    WARNING: Contents of $BACKUP_DEST_DIR are rotated.				    Directories named 'backup.\$i' will eventually be DELETED.				    We keep backups from every day for 7 days (1-8),				    then every week for 4 weeks (9-12),				    then every month for 3 months (13-15).								    You may wish to add this to your crontab using 'crontab -e'				    #  Back up files: $SOURCE_DIR to $BACKUP_DEST_DIR				    #+ every night at 3:15 am				         15 03 * * * /home/$LOCAL_USER/bin/nightly-backup_firewire-hdd.sh								    Don't forget to verify the backups are working,				    especially if you don't read cron's mail!"					ENDOFTEXT				   exit $E_COMMANDLINE				fi												# Parse the options.				# ==================								if [ "$DRY_RUN" == "true" ]; then				  DRY_RUN="-n"				  echo "WARNING:"				  echo "THIS IS A 'DRY RUN'!"				  echo "No data will actually be transferred!"				else				  DRY_RUN=""				fi								if [ "$VERBOSE" == "true" ]; then				  VERBOSE="-v"				else				  VERBOSE=""				fi								if [ "$COMPRESS" == "true" ]; then				  COMPRESS="-z"				else				  COMPRESS=""				fi												#  Every week (actually of 8 days) and every month,				#+ extra backups are preserved.				DAY_OF_MONTH=`date +%d`            # Day of month (01..31).				if [ $DAY_OF_MONTH = 01 ]; then    # First of month.				  MONTHSTART=true				elif [ $DAY_OF_MONTH = 08 \				    -o $DAY_OF_MONTH = 16 \				    -o $DAY_OF_MONTH = 24 ]; then				    # Day 8,16,24  (use 8, not 7 to better handle 31-day months)				      WEEKSTART=true				fi																#  Check that the HDD is mounted.				#  At least, check that *something* is mounted here!				#  We can use something unique to the device, rather than just guessing				#+ the scsi-id by having an appropriate udev rule in				#+ /etc/udev/rules.d/10-rules.local				#+ and by putting a relevant entry in /etc/fstab.				#  Eg: this udev rule:				# BUS="scsi", KERNEL="sd*", SYSFS{vendor}="WDC WD16",				# SYSFS{model}="00JB-00GVA0     ", NAME="%k", SYMLINK="lacie_1394d%n"								if mount | grep $MOUNT_POINT >/dev/null; then				  echo "Mount point $MOUNT_POINT is indeed mounted. OK"				else				  echo -n "Attempting to mount $MOUNT_POINT..."					           # If it isn't mounted, try to mount it.				  sudo mount $MOUNT_POINT 2>/dev/null								  if mount | grep $MOUNT_POINT >/dev/null; then				    UNMOUNT_LATER=TRUE				    echo "OK"				    #  Note: Ensure that this is also unmounted				    #+ if we exit prematurely with failure.				  else				    echo "FAILED"				    echo -e "Nothing is mounted at $MOUNT_POINT. BACKUP FAILED!"				    exit $E_MOUNT_FAIL				  fi				fi												# Check that source dir exists and is readable.				if [ ! -r  $SOURCE_DIR ] ; then				  echo "$SOURCE_DIR does not exist, or cannot be read. BACKUP FAILED."				  exit $E_NOSOURCEDIR				fi												# Check that the backup directory structure is as it should be.				# If not, create it.				# Create the subdirectories.				# Note that backup.0 will be created as needed by rsync.								for ((i=1;i				  if [ ! -d $BACKUP_DEST_DIR/backup.$i ]; then				    if /bin/mkdir -p $BACKUP_DEST_DIR/backup.$i ; then				    #  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^  No [ ] test brackets. Why?				      echo "Warning: directory $BACKUP_DEST_DIR/backup.$i is missing,"				      echo "or was not initialised. (Re-)creating it."				    else				      echo "ERROR: directory $BACKUP_DEST_DIR/backup.$i"				      echo "is missing and could not be created."				    if  [ "$UNMOUNT_LATER" == "TRUE" ]; then				        # Before we exit, unmount the mount point if necessary.				        cd					sudo umount $MOUNT_POINT &&					echo "Unmounted $MOUNT_POINT again. Giving up."				    fi				      exit $E_UNMOUNTED				  fi				fi				done												#  Set the permission to 700 for security				#+ on an otherwise permissive multi-user system.				if ! /bin/chmod 700 $BACKUP_DEST_DIR ; then				  echo "ERROR: Could not set permissions on $BACKUP_DEST_DIR to 700."								  if  [ "$UNMOUNT_LATER" == "TRUE" ]; then				  # Before we exit, unmount the mount point if necessary.				     cd ; sudo umount $MOUNT_POINT \				     && echo "Unmounted $MOUNT_POINT again. Giving up."				  fi								  exit $E_UNMOUNTED				fi								# Create the symlink: current -> backup.1 if required.				# A failure here is not critical.				cd $BACKUP_DEST_DIR				if [ ! -h current ] ; then				  if ! /bin/ln -s backup.1 current ; then				    echo "WARNING: could not create symlink current -> backup.1"				  fi				fi												# Now, do the rsync.				echo "Now doing backup with rsync..."				echo "Source dir: $SOURCE_DIR"				echo -e "Backup destination dir: $BACKUP_DEST_DIR\n"												/usr/bin/rsync $DRY_RUN $VERBOSE -a -S --delete --modify-window=60 \				--link-dest=../backup.1 $SOURCE_DIR $BACKUP_DEST_DIR/backup.0/								#  Only warn, rather than exit if the rsync failed,				#+ since it may only be a minor problem.				#  E.g., if one file is not readable, rsync will fail.				#  This shouldn't prevent the rotation.				#  Not using, e.g., `date +%a`  since these directories				#+ are just full of links and don't consume *that much* space.								if [ $? != 0 ]; then				  BACKUP_JUSTINCASE=backup.`date +%F_%T`.justincase				  echo "WARNING: the rsync process did not entirely succeed."				  echo "Something might be wrong."				  echo "Saving an extra copy at: $BACKUP_JUSTINCASE"				  echo "WARNING: if this occurs regularly, a LOT of space will be consumed,"				  echo "even though these are just hard-links!"				fi								# Save a readme in the backup parent directory.				# Save another one in the recent subdirectory.				echo "Backup of $SOURCE_DIR on `hostname` was last run on \				`date`" > $BACKUP_DEST_DIR/README.txt				echo "This backup of $SOURCE_DIR on `hostname` was created on \				`date`" > $BACKUP_DEST_DIR/backup.0/README.txt								# If we are not in a dry run, rotate the backups.				[ -z "$DRY_RUN" ] &&								  #  Check how full the backup disk is.				  #  Warn if 90%. if 98% or more, we'll probably fail, so give up.				  #  (Note: df can output to more than one line.)				  #  We test this here, rather than before				  #+ so that rsync may possibly have a chance.				  DISK_FULL_PERCENT=`/bin/df $BACKUP_DEST_DIR |				  tr "\n" ' ' | awk '{print $12}' | grep -oE [0-9]+ `				  echo "Disk space check on backup partition \				  $MOUNT_POINT $DISK_FULL_PERCENT% full."				  if [ $DISK_FULL_PERCENT -gt 90 ]; then				    echo "Warning: Disk is greater than 90% full."				  fi				  if [ $DISK_FULL_PERCENT -gt 98 ]; then				    echo "Error: Disk is full! Giving up."				      if  [ "$UNMOUNT_LATER" == "TRUE" ]; then				        # Before we exit, unmount the mount point if necessary.				        cd; sudo umount $MOUNT_POINT &&				        echo "Unmounted $MOUNT_POINT again. Giving up."				      fi				    exit $E_UNMOUNTED				  fi												 # Create an extra backup.				 # If this copy fails, give up.				 if [ -n "$BACKUP_JUSTINCASE" ]; then				   if ! /bin/cp -al $BACKUP_DEST_DIR/backup.0 \				      $BACKUP_DEST_DIR/$BACKUP_JUSTINCASE				   then				     echo "ERROR: Failed to create extra copy \				     $BACKUP_DEST_DIR/$BACKUP_JUSTINCASE"				     if  [ "$UNMOUNT_LATER" == "TRUE" ]; then				       # Before we exit, unmount the mount point if necessary.				       cd ;sudo umount $MOUNT_POINT &&				       echo "Unmounted $MOUNT_POINT again. Giving up."				     fi				     exit $E_UNMOUNTED				   fi				 fi												 # At start of month, rotate the oldest 8.				 if [ "$MONTHSTART" == "true" ]; then				   echo -e "\nStart of month. \				   Removing oldest backup: $BACKUP_DEST_DIR/backup.15"  &&				   /bin/rm -rf  $BACKUP_DEST_DIR/backup.15  &&				   echo "Rotating monthly,weekly backups: \				   $BACKUP_DEST_DIR/backup.[8-14] -> $BACKUP_DEST_DIR/backup.[9-15]"  &&				     /bin/mv $BACKUP_DEST_DIR/backup.14 $BACKUP_DEST_DIR/backup.15  &&				     /bin/mv $BACKUP_DEST_DIR/backup.13 $BACKUP_DEST_DIR/backup.14  &&				     /bin/mv $BACKUP_DEST_DIR/backup.12 $BACKUP_DEST_DIR/backup.13  &&				     /bin/mv $BACKUP_DEST_DIR/backup.11 $BACKUP_DEST_DIR/backup.12  &&				     /bin/mv $BACKUP_DEST_DIR/backup.10 $BACKUP_DEST_DIR/backup.11  &&				     /bin/mv $BACKUP_DEST_DIR/backup.9 $BACKUP_DEST_DIR/backup.10  &&				     /bin/mv $BACKUP_DEST_DIR/backup.8 $BACKUP_DEST_DIR/backup.9								 # At start of week, rotate the second-oldest 4.				 elif [ "$WEEKSTART" == "true" ]; then				   echo -e "\nStart of week. \				   Removing oldest weekly backup: $BACKUP_DEST_DIR/backup.12"  &&				   /bin/rm -rf  $BACKUP_DEST_DIR/backup.12  &&								   echo "Rotating weekly backups: \				   $BACKUP_DEST_DIR/backup.[8-11] -> $BACKUP_DEST_DIR/backup.[9-12]"  &&				     /bin/mv $BACKUP_DEST_DIR/backup.11 $BACKUP_DEST_DIR/backup.12  &&				     /bin/mv $BACKUP_DEST_DIR/backup.10 $BACKUP_DEST_DIR/backup.11  &&				     /bin/mv $BACKUP_DEST_DIR/backup.9 $BACKUP_DEST_DIR/backup.10  &&				     /bin/mv $BACKUP_DEST_DIR/backup.8 $BACKUP_DEST_DIR/backup.9								 else				   echo -e "\nRemoving oldest daily backup: $BACKUP_DEST_DIR/backup.8"  &&				     /bin/rm -rf  $BACKUP_DEST_DIR/backup.8								 fi  &&								 # Every day, rotate the newest 8.				 echo "Rotating daily backups: \				 $BACKUP_DEST_DIR/backup.[1-7] -> $BACKUP_DEST_DIR/backup.[2-8]"  &&				     /bin/mv $BACKUP_DEST_DIR/backup.7 $BACKUP_DEST_DIR/backup.8  &&				     /bin/mv $BACKUP_DEST_DIR/backup.6 $BACKUP_DEST_DIR/backup.7  &&				     /bin/mv $BACKUP_DEST_DIR/backup.5 $BACKUP_DEST_DIR/backup.6  &&				     /bin/mv $BACKUP_DEST_DIR/backup.4 $BACKUP_DEST_DIR/backup.5  &&				     /bin/mv $BACKUP_DEST_DIR/backup.3 $BACKUP_DEST_DIR/backup.4  &&				     /bin/mv $BACKUP_DEST_DIR/backup.2 $BACKUP_DEST_DIR/backup.3  &&				     /bin/mv $BACKUP_DEST_DIR/backup.1 $BACKUP_DEST_DIR/backup.2  &&				     /bin/mv $BACKUP_DEST_DIR/backup.0 $BACKUP_DEST_DIR/backup.1  &&								 SUCCESS=true												if  [ "$UNMOUNT_LATER" == "TRUE" ]; then				  # Unmount the mount point if it wasn't mounted to begin with.				  cd ; sudo umount $MOUNT_POINT && echo "Unmounted $MOUNT_POINT again."				fi												if [ "$SUCCESS" == "true" ]; then				  echo 'SUCCESS!'				  exit 0				fi								# Should have already exited if backup worked.				echo 'BACKUP FAILED! Is this just a dry run? Is the disk full?) '				exit $E_BACKUP							

相关资源