Time Machine is a useful backup service for Mac, but deleting multiple backups is cumbersome. This script allows mass deletion of unwanted backups while allowing specified important backups to remain.I recently ran out of space on an external drive I was using as a Time Machine backup location, and though there were several old backups I didn't need any more, there were a few specific backups I needed to preserve. Since backup deletion through Time Machine's UI is clunky and limited to individual deletions, I looked around for a script to do what I needed. After not finding a perfect match, I wrote this.I have been considering posting this elsewhere so people in my situation could benefit from it, but since I have no experience with bash or the nitty-gritty of Time Machine backups, I wanted to make sure I wasn't missing anything obvious that could potentially cause someone to lose data.I've tested it pretty thoroughly on my setup (OSX 10.10.5 with a single Time Machine archive on an external, non-Time-Capsule drive), but I'm new to this and shouldn't disseminate code dealing in such a sensitive area without being sure it's (reasonably) bulletproof.#!/bin/bashsudo_command=sudo bash $(cd $(dirname $0) && pwd)/$(basename ${BASH_SOURCE[0]})while [[ $# -gt 0 ]]do    option_name=$1    case $option_name in        #This many backups will be deleted        -a|--amount-to-delete)            shift            amount_of_backups_to_delete=$1        ;;        #The default is to delete oldest to newest        -n|--newest-to-oldest)            delete_newest_to_oldest=true        ;;        #Test run        -t|--test-run)            test_run=true        ;;        #Print help        -h|--help)        echo This script deletes a certain amount of Time Machine backups that are no longer needed. If there are important backups you never want to delete, add them to the saved_backup_names array in this file.        echo OPTIONS        echo -a (--amount-to-delete) <n>        echo     This required option  specifies how many backups should be deleted. n should be an integer greater than 0 or \all\ to delete all unwanted backups.        echo -n (--newest-to-oldest)        echo     This optional option changes the delete order from the default of oldest to newest.        echo -t (--test-run)        echo     This optional option runs the entire script as normal but substitutes the \delete\ verb of the deletion command with a fake verb so the deletions do not occur.        echo     This is the closest you can get to seeing what will happen without actually performing the deletes.        echo        echo EXAMPLE USAGE        echo     $sudo_command -a 4 -t        echo     $sudo_command -a all --newest-to-oldest        exit        ;;        *)        #Unrecognized option        echo '$option_name' is not a valid option.        ;;    esac    #Move to the next option    shiftdoneif [[ $EUID -ne 0 ]]then  echo You must run this as root. Use this command:  echo     $sudo_command $@  exitfi#If --amount-to-delete wasn't provided, exitif [[ -z $amount_of_backups_to_delete ]]then    echo Missing required option: --amount-to-delete <n>    exitfi#If --newest-to-oldest wasn't provided, set the flag to falseif [[ -z $delete_newest_to_oldest ]]then    delete_newest_to_oldest=falsefi#If --test-run wasn't provided, set the flag to falseif [[ -z $test_run ]]then    test_run=falsefi#Array of backup names for backups that will NOT be deleted#If there is a benchmark backup that should never be deleted by this script, add it to this arraysaved_backup_names=(    2014-05-17-094303    2014-06-15-093106    2014-06-29-133847    2015-01-02-145324    2015-02-18-103203    2015-07-25-001743    2015-09-12-123932    2015-12-12-025214    2016-12-16-044517)#Get an array of absolute paths to all remaining backupsall_backup_paths=($(/usr/bin/tmutil listbackups))if [[ $amount_of_backups_to_delete == all ]]then    amount_of_backups_to_delete=${#all_backup_paths[@]}elif [[ $amount_of_backups_to_delete -lt 1 ]]then    echo --amount-to-delete must be > 0    exitfi#Build an array of paths to the backups that will be deleted so the list can be approved by the useramount_of_backups_added=0for ((i = 0; i < ${#all_backup_paths[@]} && $amount_of_backups_added < $amount_of_backups_to_delete; i++))do    #Offset index from the last item if the newest backups should be deleted first    index=$i    if [[ $delete_newest_to_oldest = true ]]    then        index=`expr ${#all_backup_paths[@]} - 1 - $index`    fi    backup_name=$(basename ${all_backup_paths[$index]})    able_to_delete=true    for name in ${saved_backup_names[@]}    do        #If the current backup trying to be deleted is in the list of saved names, don't delete it        if [[ $name == $backup_name ]]        then            able_to_delete=false        fi    done    if [[ $able_to_delete = true ]]    then        ((amount_of_backups_added++))        to_delete_backup_paths+=(${all_backup_paths[$index]})    fidone#Print a list of the protected and to-be-deleted backups and prompt for confirmationconfirmation_message=I have reviewed the deletion list.echo These backups are protected. They will not be deleted.echo --------------------------------------------------------------------------------for name in ${saved_backup_names[@]}do  echo $namedoneechoecho These backups will be deleted.echo --------------------------------------------------------------------------------for backup_path in ${to_delete_backup_paths[@]}do    basename $backup_pathdoneechoread -p Enter \$confirmation_message\ sans quotes to start the deletion.  echoif [[ $REPLY == $confirmation_message ]]then    for ((i = 0; i < ${#to_delete_backup_paths[@]}; i++))    do        date=$(date)        echo [$date]    Starting deletion for ${to_delete_backup_paths[$i]}        if [[ $test_run = true ]]        then            sudo time /usr/bin/tmutil this_is_a_test_run ${to_delete_backup_paths[$i]}        else            sudo time /usr/bin/tmutil delete ${to_delete_backup_paths[$i]}        fi        date=$(date)        echo [$date]    Finished    doneelse    echo The confirmation message didn't match, so nothing was deleted.fi
Selective Time Machine backup deletion
bash;macos