2010/06/28

Recipes for tm-diff (Time Machine difference)

A few recipes for using the tm-diff.sh script that I posted earlier (see link for details):

  • Ignore errors/warnings (ex: "Permission denied"):
    tm-diff.sh folder1 folder2 2> /dev/null

  • Find all files, regardless of their privileges/permissions:
    sudo tm-diff.sh folder1 folder2

  • Display disk usage, in "human-readable" sizes (ex: KB, MB, GB...):
    tm-diff.sh folder1 folder2 | while read f; do du -h "$f"; done

  • Display disk usage, with a grand total at the end (sizes in KB):
    tm-diff.sh folder1 folder2 | while read f; do du -k "$f"; done | awk '{ sum += $1; print; } END { print sum; }'

  • Display the largest 50 files (sizes in MB):
    tm-diff.sh folder1 folder2 | while read f; do du -m "$f"; done | sort -n | head -50

  • Display the smallest 100 files (sizes in KB):
    tm-diff.sh folder1 folder2 | while read f; do du -k "$f"; done | sort -rn | head -100

  • Display a full listing (with mode/privileges, owner, group...):
    tm-diff.sh folder1 folder2 | while read f; do ls -l -h "$f"; done


Notes:
  1. This presumes you've set your PATH so it'll find the tm-diff.sh script. (Or use its full path.)

  2. In the commands above, "folder1" and "folder2" of course represent the paths to the two Time Machine backup folders to compare; they'll look something like:
    /VOLUMENAME/Backups.backupdb/USERNAME/2009-07-20-091153

  3. The script explicitly searches for regular files only; no directories or other special files.

  4. I use a read loop, since this will get the full path, including "special" characters like spaces and double-quotes.

  5. Sizes are in the classic style ("as God intended"): KB = 1024 bytes; MB = 1024 KB; GB = 1024 MB ...

  6. Most Time Machine backups contain tens of thousands of files, so these will take awhile. The ones that sort will display no files, until all of them have been found, to be sorted - so they will seem to take even longer.

2010/06/27

Show differences between two Time Machine backups

Below is a quick Bash script to display the difference between two Time Machine backups.

The output is simply the pathnames of the files that were added to Time Machine in that time period. This may of course be piped to another command/script to provide further info - say, the amount of space used.

Cheat: Provide a simple date (formatted the same way that Time Machine does) instead of the "older" backup pathname, and it'll work whether or not there was a backup then. (The order of the arguments is unimportant; the script will figure it out.)

#!/bin/bash

LF=$'\n'
usage="Usage: $(basename $0) Time-Machine-folder-1 Time-Machine-folder-2"
usage=$usage$LF"(Compare the two Time Machine backup folders;"
usage=$usage"find and display files that were backed up in that time period.)"

function tweakDate { # to a fmt understood by find cmd
echo "$1" | awk -v FS="" '{print $1$2$3$4$5$6$7$8$9$10" "$12$13":"$14$15":"$16$17}'
}

if [ ! $# == 2 ] ; then
{
echo "$0 requires two arguments; the Time Machine folders to compare." >&2
echo "$usage" >&2
exit 1
}
fi

baseName1=$(basename $1)
baseName2=$(basename $2)

# NB: operator must be escaped or will signify redirection
if [ "$baseName1" \< "$baseName2" ] ; then
{
olderFldr=$1
recentFldr=$2
olderFldrName=$baseName1
recentFldrName=$baseName2
}
else
{
reverse=TRUE
olderFldr=$2
recentFldr=$1
olderFldrName=$baseName2
recentFldrName=$baseName1
}
fi

if [ ! -d "$olderFldr" ] ; then
{
echo -n "Warning: $olderFldr doesn't seem to exist;" >&2
echo " maybe you're just using it to specify a date?..." >&2
}
fi

olderFldrParent=$(dirname $olderFldr)
recentFldrParent=$(dirname $recentFldr)

if [ ! $olderFldrParent == $recentFldrParent ] ; then
{
echo -n "Warning: These folders are not in the same parent folder;" >&2
echo " this may not be what you want..." >&2
}
fi

olderFldrDate=$(tweakDate $olderFldrName)
recentFldrDate=$(tweakDate $recentFldrName)

if [ ! -d "$recentFldr" ] ; then
{
latestBackup="${recentFldrParent}/$(ls -1 $recentFldrParent | tail -2 | head -1)"

echo "Can't find $recentFldr; searching the latest backup" >&2
echo " ($latestBackup)" >&2
echo " for files modified between $olderFldrDate and $recentFldrDate." >&2
echo " This may take awhile..." >&2
echo $LF >&2

find -x "$latestBackup" -type f -newermt "$olderFldrDate" \! -newermt "$recentFldrDate" -print
}
else
{
echo "Now searching for backups in $recentFldrName" >&2
echo " that are more recent than $olderFldrDate." >&2
echo " This may take awhile..." >&2
echo $LF >&2

find -x "$recentFldr" -type f -newermt "$olderFldrDate" -print
}
fi

# eof