Posted on 07 November 2005, 21:59

Shell script to sync laptop and desktop

Here's a script I use intermittently to sync corresponding directories on my laptop and desktop computers. When I make significant changes on a certain computer I use ChronoSync. But for a file or two, this is my quick fix. Thanks to OS X FAQ for the tip regarding AFP mounting.

#!/bin/bash


# Description
# -----------------------------------------------------------------------

# mounts the current user's home directory on the server
#    $ALM_SERVER into the mount $ALM_AFP_MOUNT/...
# for more info: http://www.osxfaq.com/tips/unix-tricks/week84/tuesday.ws
# rsyncs directory from local to server


# Functions
# -----------------------------------------------------------------------

# function: usage ([error-message])
#    print out the usage lines and exit
#    optional error message printed at end of the usage line
usage ()
{
  echo "Perform rsync on specified directory within ${USER}'s local home directory \
  to corresponding location on server $ALM_SERVER."
  echo ""
  echo "Usage: ${0##*/} [-p password] [-h host] [-u user] source"
  echo "  [-p password] - password to mount $ALM_SERVER"
  echo "  [-h host] - override $ALM_SERVER as server to mount"
  echo "  [-u user] - override $USER as username to mount"
  echo "  source - the directory to be synched"
  echo ""
  if [ "$*" != "" ]; then echo "Error: $*."; fi
  exit
}

# function: exit_if_set (current-value, parameter-description)
#    called to prevent a parameter being given a value more than once
exit_if_set ()
{
  if [ "$1" != "" ]; then
    usage "$2 already has the value '$1'"
  else
    return
  fi
}


# Process parameters
# -----------------------------------------------------------------------

# If there isn't at least 1 parameter abort
if [ $# -lt 1 ]; then
  usage "Must specify source directory to sync"
fi

# process each parameter by looping and shifting
#    $2 -> $1 each iteration
#
opt=""
while [ "$1" != "" ]
do
  if [ "${1:0:1}" = "-" ]; then
    # found a -<char> option introducer
    case "$1" in
      # these options require a value, remember option for next iteration
      # error if previous iteration was also an option that required a value
      "-usage") usage;;
      "-p" | "-h" | "-u")
        if [ "$opt" = "" ]; then
          opt="$1"
        else
          usage "no value given for $opt"
        fi
      ;;

      # invalid option
      *) usage "invalid option $1";;
    esac
  else
    case "$opt" in
      # previous iteration was option that required a value, set the value
      "-p") exit_if_set "$password" "password"; password="$1";;
      "-h") exit_if_set "$host" "host"; host="$1";;
      "-u") exit_if_set "$user" "user"; user="$1";;
      "") exit_if_set "$source_dir" "source directory"; source_dir="$1";;
    esac
    # a value has been found for -<char>, so reset this flag
    opt=""
  fi
shift
done

# this case is where the last option was -<char>, thus no value has been given
if [ "$opt" != "" ]; then
    usage "no value given for $opt"
fi

# verify source directory
working_dir=`pwd`
source_dir=`echo $source_dir | sed "s#^~#$HOME#"`
source_dir=`echo $source_dir | sed "s#^\([^/]\)#$HOME\/\1#"`
source_dir=`echo $source_dir | sed "s#\/\\$##"`
source_dir=`echo $source_dir | sed "s#^\.\/#$working_dir\/#"`

if [ $source_dir = "." ]; then
  source_dir=$working_dir
fi

if [ ! -d $source_dir ]; then
  usage "Source [$source_dir] not a directory"
fi

if [ ! `echo $source_dir | grep $HOME` ]; then
  usage "Source [$source_dir] is not within your user directory"
fi

if [ `echo $source_dir | grep "\.\."` ]; then
  usage "Source directory cannot contain '..'"
fi

# set default values for optional parameters
if [ "$host" = "" ]; then host="$ALM_SERVER"; fi
if [ "$user" = "" ]; then user="$USER"; fi


# Main
# -----------------------------------------------------------------------

destination_dir=`echo $source_dir | sed "s#$HOME#$ALM_AFP_MOUNT/$host/$user#"`
script_mount=$HOME/Documents/bin/mount-user.sh

# mount server if necessary
if [ ! -e "$ALM_AFP_MOUNT/$host/$user" ]; then
  if [ -z "$password" ]; then
    $script_mount -u $user -h $host
  else
    $script_mount -u $user -p $password -h $host
  fi
fi

# test destination
if [ ! -d "$destination_dir" ]; then
  usage "Destination directory does not exist"
fi

# confirm sync
echo "Confirm command :"
echo "  rsync -avuzb --exclude '*~' --exclude '.DS_Store' --exclude '.localized' $source_dir/ $destination_dir/ "
echo "Run command ? [y/N]"
read ASK
if [ "$ASK" = "y" ] || [ "$ASK" = "Y" ]; then
  rsync -avuzb --exclude '*~' --exclude '.DS_Store' --exclude '.localized' $source_dir/ $destination_dir/
fi

NB: The globals $ALM_ are defined in my <code>.bash_profile</code> as follows. The values correspond to the Computer Name specified in the System Preferences Sharing panel:

# set afp stuff for working between workstation and laptop
export ALM_AFP_MOUNT=/Volumes
if [ `hostname -s` = "desk" ]; then
  export ALM_SERVER=lap.local
else
  export ALM_SERVER=desk.local
fi

Download the shell script

Add a comment?

Sign in to add your own comments.