I'm looking to automate a backup process that involves transporting backup files (with names in the form "*.savf") first onto a Mac Mini (running Yosemite), and then, once they're on the Mini, moving them from where they were initially placed onto external USB drives. This is a process that was formerly running on a very large, very noisy, and very worn-out Linux box.

So far, I have the files arriving on the Mini. But can anybody point me towards an easy way to automate moving them to the external drives?

You want details, here they are:

The two external boxes being backed up (AS/400s, hence the "SAVF" extensions), either every evening at a specified time, or when they are told to shut themselves down, will run a program that checks specified libraries to see if there is anything in them that needs backing up. If a library needs backing up, it will be saved to an AS/400-specific construct called a "save file," and then FTP'd to the backup server (each has its own account on the backup server, with its own home directory).

On the Linux backup server, because I could not work out a way for it to FTP directly to the external drives, there was a shell script, running as a cron job, under root authority, which copied those save files to the external drives, then deleted them from the home directories.

I have the first part working very nicely on the Mac. Not sure how to make the second part work.

5/8/2023: I've just successfully reverse-engineered my own shell script:

cd /Users/foo
cp *.savf /Volumes/BACKUP/foo
mv *.savf /Volumes/BACKUP2/foo

cd /Users/bar
cp *.savf /Volumes/BACKUP/bar
mv *.savf /Volumes/BACKUP2/bar

Now, to make it execute at a specific time of day, under root authority, and ignore all errors . . .

**** May 10th ****

I now have a plist in /Library/LaunchDaemons (put in late yesterday afternoon), BUT IT DIDN'T WORK! It's called "sweep.plist," and it is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">

And I did a launchctl load /Library/LaunchDaemons/sweep.plist (either sudo'd or in a sudo bash) once it was in place. I'm absolutely certain that after I did so yesterday, "sweep" showed up in a launchctl list, but it didn't execute, and it no longer shows up when I do a launchctl list.

Any idea where to look for the problem?

New: I just checked the system log, and found this: May 10 08:00:05 Europas-Mac-mini com.apple.xpc.launchd[1] (sweep[1299]): Program specified by service is not a Mach-O executable file.

Looking at the shell script with a ls -l, it shows permissions as -rwxr-xr-x@

  • Can you edit the question with some details like what this “automation” looks like? Is it on a schedule, an event, or something else? Are these USB drives (and their mount points) going to be static? What did the Linux process look like?
    – Allan
    Commented May 5, 2023 at 23:36
  • You could use Time Machine on the Mini to backup just the specific directories to multiple rotating external drives. In System Preferences > Time Machine > Options ... use the "Exclude items" logic to set the directories you want backed-up, then uncheck System Preferences > Time Machine > Back Up Automatically. Executing the Terminal command tmutil startbackup will then, well, start a backup. Find a way to schedule the tmutil command, and Bob's your Uncle.
    – IconDaemon
    Commented May 6, 2023 at 1:47
  • And you can't use the same shell script now for some reason? Commented May 6, 2023 at 3:11
  • I may not be able to access the original shell script, or the original crontab entry that tripped it: the Linux box that was formerly the backup controller appears to have crapped out completely, and won't even power up. Commented May 8, 2023 at 16:58
  • And looking at the Automator docs, I'm not sure if that's even relevant, even though it apparently can schedule things as Calendar alarms. And no, I don't want to involve Time Machine. Looking at launchd.info now. Hmm. "launchd differentiates between agents and daemons. The main difference is that an agent is run on behalf of the logged in user while a daemon runs on behalf of the root user or any user you specify with the UserName key." Commented May 8, 2023 at 17:14

3 Answers 3



Apple provide launchd with macOS for managing daemons and other background processes, including scripts:

Script management with launchd in Terminal on Mac

The launchd process is used by macOS to manage daemons and agents, and you can use it to run your shell scripts. You don’t interact with launchd directly; instead you use the launchctl command to load or unload launchd daemons and agents.


cron remains available on macOS and is a valid option for running your script to a schedule. Apple have deprecated cron in favour of launchd. The tool is deprecated because cron is not considered energy efficient.

However, cron works and is reliable.

Third Party

If you are happy to use a third party tool for scheduling your script, many options are available, including:

Power Manager

I am an engineer behind Power Manager, which is a tool that can run your shell script as root.

The following two links show two different approaches – one with an external script, the other with an inline script:

Power Manager on macOS - run a script daily as root

  • 1
    I wasn't actually looking for a third-party solution, and I've already begun studying launchd (since I'm certainly not married to cron, either). But thanks. It looks like Power Manager is the first third-party option I've seen that will run under anything as old as Yosemite. And more than that, thanks for mentioning launchd and cron, which gives me some confirmation for where I was already leaning. Commented May 9, 2023 at 16:14
  • If you need even older macOS support, see dssw.co.uk/powermanager/legacy and if you need help with creating specific launchd plist files, do ask new questions. Commented May 10, 2023 at 12:06
  • For some reason, even though I thought I did everything right, it didn't work. I put what I know so far in this question, and started a separate question (cross-referencing this one) about the launchd problem. Commented May 10, 2023 at 17:45

Earlier today, I found something: https://stackoverflow.com/a/39062525/3654526

It seems that once I changed the generic shebang to one specifying a shell (from #! to #!/bin/bash) and changed the time the script's supposed to execute, it worked.

Unfortunately, I also discovered that the spontaneously disconnecting USB drive wasn't just from the box going to sleep: it seems that the drive is starting to flake out, and the box going to sleep was just a trigger. Time to retire the Seagate and get a new drive. Then again, that's why I'm backing up to two separate USB drives.


For something as simple as this, I just stick with the old-fashioned way.

First, since you want it done as root, sudo sh or sudo bash or sudo zsh according to your preference.

Then, crontab -e to edit a crontab with vim.  man 5 crontab tells the format you need.  Basically,

17  4  *  *  *  /usr/local/bin/rsync -av /Users/foo/ /Volumes/BACKUP/foo
23  4  *  *  *  /usr/local/bin/rsync -av /Users/foo/ /Volumes/BACKUP2/foo

will, ar 04:17 and 04:23, move everything in /Users/foo to the other unless it is already there.  The slash on /Users/foo is important. Without it, you'll create /Volumes/BACKUP/foo/foo  In other words,

/usr/local/bin/rsync -av /Users/foo/ /Volumes/BACKUP/foo
/usr/local/bin/rsync -av /Users/foo /Volumes/BACKUP

do the exact same thing.  man rsync for details.

launchd has a lot more capabilities than cron, but when I don't need the enhancements, I revert to the simpler “archaic” method.

rsync copies only what is missing or changed, so if you suspect any glitches, you can repeat it an hour later and it won't waste bandwidth repeating what already got copied:

17 4,5 * * * /usr/local/bin/rsync -av /Users/foo/ /Volumes/BACKUP/foo

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .