Any way to automate a Time Machine backup, mount-backup-unmount?

I’m looking for a way (script, macro, app) to automate my Time Machine backups on demand, like this:

  1. Mount the TM disk
  2. Run the TM backup
  3. Check if the backup is finished
  4. If finished, unmount the disk.

I’m not very savvy with programming but I can follow some directions and if everything fails, there’s always copy and paste. :sweat_smile:
I found some scripts searching around the web but they are a few years old. Since macOS changed a lot recently in the file system department, I decided to ask you fellow nerds for an up to date solution.
I’m running macOS Mojave 10.14.6 on an iMac.

Step 3 I’m not sure about, but before letting others jump in I’m wondering why you want to do this. What problem are you fixing?

I’m assuming that you don’t want the TM disk (which I assume is external USB) mounted all the time. I get that. But far as i know it’s not practically/easily possible to automatically push the USB plug into the Mac so that means to me that the disk plug will always be connected. So if always connected, why not take advantages of TimeMachine and let it run, basically continuously, backing up all the time? When time to remove the USB plug, just “eject” it and go. Unplugging the USB plug from the Mac is also not easily made automatic and programmable.

To get you started see https://www.macworld.com/article/2033804/control-time-machine-from-the-command-line.html which I found from a Google search “osx command line timemachine”. Might be more on the other side of the search. Take a look. For command line control of mounting/unmounting devices, see the command “diskutil”.

You can read more about these two commands in a terminal window by running “man diskutil” and “man tmutil”. And you can schedule it with “crontab”. There is a man file for that too.

Are you sure you want to do all this?

I’d do this in Keyboard Maestro. You can find some ideas in this topic.

I’m sure there’s a scriptable way to do this, with terminal commands diskutil mount and diskutil unmount, but I’m not expert enough to give advice :smile:

1 Like

Yea, I know. I use Mountain to “Unmount all and sleep” when I want to take the MacBook away. Does it very quickly.

@rms Thanks for the link. So, the reasons I don’t want to have the drive mounted all the time are:

  • The TM external HDD is attached under the desk, so everytime it spins the desk vibrates. I’m trying to hack some rubber pads to try and stop it, but still…

  • I can also hear the drive.

  • I prefer to not have it mounted just in case there’s some power outage or if the Mac crashes.

  • I really don’t need a backup that runs in the backgroung every hour.

  • I’d like to automate the process using something like a Keyboard Maestro shortcut or double click to run a script from Automator, as opposed to manually connect/mount, click to start the TM backup, unmount/disconnect. We’re Mac Power Users after all! :slight_smile:

I saw that you use Mountain.app for this. When I was researching alternatives I saw this app, but it looked like the developer abandoned it. They still mention High Sierra compatibility as a new feature on their website. Does it work fine on Mojave or Catalina?

@memex Thanks for the topic, I’ll see if I can adapt the ideas for my use case.

When I make any progress I’ll post it here, just in case anyone is interested, but any other input is appreciated nonetheless.

Although it doesn’t address all your concerns, have you thought about an SSD as the TimeMachine target?

That’s my dream! But right now a equivalent 4TB SSD is prohibitively expensive.

FWIW - I’ve heard that the way Time Machine works, it doesn’t make an SSD worth it.

You can actually do this very easily. I’ve got a script for this. Let me take a look.

Ok, so I had this mostly written already.

Save this file as /usr/local/bin/timemachine-mount-run-unmount.sh

#!/usr/bin/env zsh -f
# Purpose: 	Once you set the DEVICE,
#			this script will mount your Time Machine drive,
#			run Time Machine,
#			and then unmount the drive
#
# From:	Timothy J. Luoma
# Mail:	luomat at gmail dot com
# Date:	2020-04-20

	## To find the device, mount the Time Machine drive and then run this command in Terminal:
	#
	#	mount | egrep '^/dev/' | sed -e 's# (.*#)#g' -e 's# on /# (/#g'
	#
	# and you will see a bunch of entries like this
	#
	#	/dev/disk2s1 (/Volumes/MBA-Clone - Data)
	#	/dev/disk3s5 (/Volumes/Storage)
	# 	/dev/disk4s6 (/Volumes/MBA-Clone)
	#
	# You need to set
	#
	#	DEVICE='/dev/disk3s5'
	#
	# or whatever is correct for your Time Machine drive

DEVICE=''




################################################################################################

NAME="$0:t:r"

if [[ -e "$HOME/.path" ]]
then
	source "$HOME/.path"
else
	PATH="$HOME/scripts:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin"
fi

zmodload zsh/datetime

TIME=$(strftime "%Y-%m-%d--%H.%M.%S" "$EPOCHSECONDS")

function timestamp { strftime "%Y-%m-%d--%H.%M.%S" "$EPOCHSECONDS" }

STATUS=$(tmutil currentphase)

if [[ "$STATUS" != "BackupNotRunning" ]]
then
	echo "$NAME: Time Machine status is '$STATUS'. Should be 'BackupNotRunning'." >>/dev/stderr
	exit 0
fi

	# if you have multiple Time Machine destinations, this might not give you the right info
	# I'm assuming you only have one
TM_DRIVE_NAME=$(tmutil destinationinfo | egrep '^Name  ' | sed 's#^Name  *: ##g' | head -1)

MNTPNT="/Volumes/$TM_DRIVE_NAME"

if [[ -d "$MNTPNT" ]]
then

	echo "$NAME: '$MNTPNT' is already mounted".

else


	if [[ "$DEVICE" == "" ]]
	then
		echo "$NAME: the 'DEVICE' variable is not set" >>/dev/stderr
		exit 0
	fi

	diskutil mountDisk "$DEVICE"

fi

if [[ ! -d "$MNTPNT" ]]
then

	echo "$NAME: Failed to mount '$MNTPNT'." >>/dev/stderr
	exit 0
fi

TM_DRIVE_ID=$(tmutil destinationinfo | egrep '^ID  ' | sed 's#^ID  *: ##g' | head -1)

echo "$NAME: Starting backup at `timestamp`"

	# `caffeinate -i` is optional but keeps your Mac from sleeping
caffeinate -i tmutil startbackup --block --destination "$ID"

EXIT="$?"

if [[ "$EXIT" == "0" ]]
then
	echo "$NAME: Finished successfully at `timestamp`."

else

	echo "$NAME: Finished UN-successfully (Exit = $EXIT) at `timestamp`."

fi

while [[ -d "$MNTPNT" ]]
do

		# this will try to unmount the drive as long as it is mounted

	diskutil unmountDisk "$MNTPNT"

	sleep 10

done

exit 0
#EOF

Note that the file is probably not fully shown in your browser, so be sure you copy the whole thing.

Note that you need to run the command:

mount | egrep '^/dev/' | sed -e 's# (.*#)#g' -e 's# on /# (/#g'

and then set the DEVICE='' variable near the top of the file.

Failure to do this will cause this script to inevitably fail.

Make Executable (Mandatory)

Once the file is saved in its location, make sure it is executable:

chmod 755 /usr/local/bin/timemachine-mount-run-unmount.sh

Try it

Once you have done all of that, you can run the script like this:

/usr/local/bin/timemachine-mount-run-unmount.sh

and it should tell you what it is doing.

Optional - launchd daily operation

If you want to have this run automatically every day. save the file below as:

$HOME/Library/LaunchAgents/com.tjluoma.timemachine-mount-run-unmount.plist

Here’s the file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Label</key>
	<string>com.tjluoma.timemachine-mount-run-unmount</string>
	<key>Program</key>
	<string>/usr/local/bin/timemachine-mount-run-unmount.sh</string>
	<key>RunAtLoad</key>
	<true/>
	<key>StandardErrorPath</key>
	<string>/tmp/com.tjluoma.timemachine-mount-run-unmount.log</string>
	<key>StandardOutPath</key>
	<string>/tmp/com.tjluoma.timemachine-mount-run-unmount.log</string>
	<key>StartCalendarInterval</key>
	<dict>
		<key>Hour</key>
		<integer>1</integer>
		<key>Minute</key>
		<integer>5</integer>
	</dict>
</dict>
</plist>

Once you have that file in place, do this in Terminal (all one line):

launchctl load "$HOME/Library/LaunchAgents/com.tjluoma.timemachine-mount-run-unmount.plist"

You can look at the log file at /tmp/com.tjluoma.timemachine-mount-run-unmount.log to see if it works.

Note that the way that I have it, it will run:

  1. Whenever you log in

  2. Every dat at 1:05 a.m.

The idea here is that you might want to make sure that it runs every day when you aren’t using the computer (maybe? No judgment.)

Questions?

Let me know.

2 Likes

OMG, TJ thanks a lot. That’s awesome!
I’ll put it in place right away.

Since my computer uptime is very random It’s safer for now to use a KM or Automator trigger instead of setting a launchd schedule. I’ll definitely save the plist though, I know that it’s gonna be used sometime in the future.

1 Like

My SSD works fine???

Just wondering if just stopping Time Machine and ensuring that “put hard disks to sleep when possible” is set in system preferences would do the trick (and quite a bit simpler).

The two options to implement:

1 - Simple - Create an automator application to open system preferences, click on time machine and click the “backup automatically”. This would be like a toggle, run to turn on, run to turn off. Screen shot attached to help further.

2 - Setup a script that can either disable to enable Time Machine.
sudo tmutil disable
sudo tmutil enable

Sorry for being unclear.

What I was meaning to say was not that an SSD wouldn’t work with Time Machine, but that dramatic speed increase seen when going from a regular HDD to an SSD is not usually seen when using Time Machine, due to the way that Time Machine works (read: slow and not overly efficient). That’s why many folks are hoping for a “Time Machine 2.0” that would take advantage of SSDs, but, as mentioned elsewhere, large SSDs are still prohibitively expensive for most folks.

All of which is really a moot point, because the discussion was about the noise caused by a Time Machine HDD, which would definitely be alleviated by an SSD.

1 Like

If you are using Keyboard Maestro, you should be able to drop that script right into a Keyboard Maestro macro and not have to worry about saving it to /usr/local/bin and making it executable.

Also, if you are using it with Keyboard Maestro and not launchd there are probably some changes you’d want.

For example, when writing for launchd I tend to avoid a non-zero exit because it can prevent launchd from trying to run the script again.

With Keyboard Maestro, if something fails you want a non-zero exit because that can be used to tell Keyboard Maestro not to execute actions later in the macro.

Also, the original version output a lot of status messages, even when nothing went wrong. In launchd that’s fine because it will end up in the log. In Keyboard Maestro that can be distracting and I find it preferable to only have output if there is an error.

All of which is to say that I made some changes to the script to make it more Keyboard Maestro-friendly. And I put it in a gist, which is probably a better idea than using a code block that large in Discourse.

Thanks a million! Will get it now.

1 Like