Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

dbrewood

macrumors 6502a
Original poster
Jun 8, 2018
691
232
Manchester, UK
Guys I'm looking to use Automator to back up some files every 2 hours

Source is 'iCloud/spreadsheets'
Destination is '/myuser/Onedrive/Backup'

I've tried a script entry of:

rsync -aE --delete ~iCloud/spreadsheets "Volumes/myuser/Onedrive/Backup/"

Which fails as none of the paths can be found. I'm new to this sort of thing so any guidance would be appreciated.

The next part of the problem is working out how to automate the script to run.

Any assistance would be greatly appreciated.
 
My first guess is that the pathnames are wrong.

Rather than me guessing at how to fix them, I'll describe a procedure for you to perform, so you can see exactly what the correct pathnames are.

First, open a Terminal window. Next, type the word echo into the window, followed by at least one space. More than one space is fine, but no spaces won't work.

Now go to the Finder and locate the folders you want to find the pathnames for. Click once on them to select them, then drag them above the Terminal window, and drop them onto that window.

What should happen is that the full pathname appears in the Terminal window. You can then reactivate the Terminal window, press the RETURN key to run the command, and see the pathnames echoed to the Terminal window output.

One warning: if any of the pathnames contains an embedded space character, then the Terminal will precede each space with a single \ character (backslash). This tells the shell (command-line interpreter) that this space is part of the name, rather than being a delimiter between command parameters.

When you have Run Shell Script actions in Automator, the command lines should EITHER use quotes around a pathname with embedded spaces OR use a \ before each space, but NOT BOTH.

If you have additional questions, then please copy and paste the output from the echo command here, or the full text of the Run Shell Script that's not working. Accurate details are very important in shell command lines, and a single missing or misplaced character can lead to very different outcomes.
 
Have not dug around iCloud storage, but, believe iCloud documents are under folders under '~/Library/Mobile Documents'.

And not a OneDrive client app user, but if like Dropbox and ilk, the actual path is something like ~/OneDrive/Backup

As to how to automate, Apple recommended method is via launchd/launchctl.

 
Thanks guys I got the paths and command worked out. The following does the job nicely:

Code:
rsync -aE --delete "/Users/<myuser>/Library/Mobile Documents/com~apple~CloudDocs/Keys" "/Users/<myuser>/OneDrive/Mac Mini Backup/"

So now I need to schedule it to run. I've read through the reference on Creating Launch agent and that seems way over complex. Does MacOS not have anything like the Windows Task Scheduler at all?
[automerge]1571924712[/automerge]

Right it looks like I need to use something like:

Code:
<?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>BackupKeyFiles</key>
        <string>local.restart</string>
        <key>Program</key>
        <string>/PATH TO SCRIPT</string>
        <key>StartInterval</key>
        <integer>7200</integer>
        <true/>
    </dict>

So does that mean I need to take the script above out of Automator and save it as a text file somewhere with the .scpt extender and then call that in the 'PATH TO SCRIPT' part of the above?

This seems amazingly complex......
 
Last edited:
Okay after a bit of thought I've produced these notes - I now get the errors you can see in red.

Process for producing a script to copy files and then automate the process.



Example command line to do the backup:

rsync -aE --delete "/Users/daronbrewood/Library/Mobile Documents/com~apple~CloudDocs/Keys" "/Users/daronbrewood/OneDrive/Mac Mini Backup/"



This should then be turned into a script file such as:


#!/bin/bash
rsync -aE --delete "/Users/daronbrewood/Library/Mobile Documents/com~apple~CloudDocs/Keys" "/Users/daronbrewood/OneDrive/Mac Mini Backup/"


and saved in:



/usr/local/bin



e.g.



/usr/local/bin/backupkeyfiles.sh



Once the script has been created it then needs to be run on a schedule:



This will be done via a demon, and the following will run every 2 hours (7200 seconds)


<?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>BackupKeyFiles</key>

<string>local.restart</string>

<key>Program</key>

<string>/usr/local/bin/backupkeyfiles.sh</string>

<key>StartInterval</key>

<integer>7200</integer>

<true/>

</dict>


The demon file is to be named ‘com.daron.back-up-key-files.plist’ and saved into ‘~/Library/LaunchAgents/’ as that position will allow the script to run when only myself is logged on.



Note ~ indicates home directory.



(Reference: https://stackoverflow.com/questions/132955/how-do-i-set-a-task-to-run-every-so-often)





Set the permissions on both files in Terminal:



chmod +x backupkeyfiles.sh

chmod +x com.daron.back-up-key-files.plist



To start the daemon running execute the terminal app and run:



launchctl load ~/Library/LaunchAgents/ com.daron.back-up-key-files





Problems on looking to start the demon I get:



daronbrewood@Darons-Mini-54 LaunchAgents % launchctl load ~/Library/LaunchAgents/ com.daron.back-up-key-files

/Users/daronbrewood/Library/LaunchAgents/com.hp.devicemonitor.plist: service already loaded

/Users/daronbrewood/Library/LaunchAgents/com.daron.back-up-key-files.plist: Invalid property list

/Users/daronbrewood/Library/LaunchAgents/com.microsoft.OneDriveMigrationLauncher.plist: Service is disabled

/Users/daronbrewood/Library/LaunchAgents/com.dropbox.DropboxMacUpdate.agent.plist: service already loaded

/Users/daronbrewood/Library/LaunchAgents/com.daron.back-up-key-files: Not a directory

/Users/daronbrewood/Library/LaunchAgents/com.macpaw.CleanMyMac4.Updater.plist: service already loaded

daronbrewood@Darons-Mini-54 LaunchAgents %





Again any assistance appreciated.
 
First, the last few lines of your plist file are incorrect. Replace this:
Code:
<integer>7200</integer>
</true>
</dict>
with this:
Code:
<integer>7200</integer>
</dict>
</plist>


Second, in this command-line:
Code:
 launchctl load ~/Library/LaunchAgents/ com.daron.back-up-key-files
there's a misplaced space between "LaunchAgents/" and "com.daron.back-up-key-files".

This is an example of the accuracy needed for command-lines. With the space, the 'launchctl load' command takes the first parameter (~/Library/LaunchAgents/) as a directory name, and tries loading every plist therein. Since most of those were already loaded when you logged in, i.e. they automatically started at login, then 'launchctl' complains that the service each one represents is already loaded. It then takes "com.daron.back-up-key-files" as a second parameter, and since no such file exists, it rejects it.

Note that the com.daron.back-up-key-files.plist residing in LaunchAgents is not a valid plist file, because of the error I noted above. Thus, when 'launchctl' tries to load it, it complains that it's an "Invalid property list".

If you remove the space, then things should work, after correcting the first plist problem above. The command-line should be:
Code:
 launchctl load ~/Library/LaunchAgents/com.daron.back-up-key-files.plist
Note there is no longer a space before "com.", so launchctl sees one filename parameter, not two. I also added ".plist" to the pathname, although I'm not sure whether your version of launchctl would need it or not. I think it will, so try it that way first.

You can also test by logging out, logging back in, then looking at the output of:
Code:
 launchctl list
If you see your task in the list, then it loaded correctly at login. If not, it didn't. This takes longer than using 'launchctl' commands, but is less prone to typing errors in Terminal.
 
Thanks for that, very much appreciated. I made the suggested changes to the daemon file and altered the command line. I now get only one error.

The plist now reads as:

Code:
<?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>BackupKeyFiles</key>
        <string>local.restart</string>
        <key>Program</key>
        <string>/usr/local/bin/backupkeyfiles.sh</string>
        <key>StartInterval</key>
        <integer>7200</integer>
    </dict>
</plist>

And the error shown was:

Code:
daronbrewood@Darons-Mini-139 ~ % launchctl load ~/Library/LaunchAgents/com.daron.back-up-key-files.plist
/Users/daronbrewood/Library/LaunchAgents/com.daron.back-up-key-files.plist: Invalid or missing service identifier

So near and yet so far :)
 
Looking at one of my existing agent plists, I see this:
Code:
<key>Label</key>
<string>task-lites-off</string>
So it looks like you need something like that. I happen to use the convention of all-lower-case where hyphens-separate-words. SomePeopleLike the CamelCase convention instead. The only thing that matters to the system is that it's unique.

The absence of a Label in what you posted earlier leads me to ask: How did you learn how to make plist files for agents? Did you read an article somewhere? Can you post its URL? Did you look at an existing plist file? Which one?

Sometimes the path one took to reach a point can be informative.
 
Okay plist now reads as per:

Code:
<?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>task-lites-off</string>
        <string>local.restart</string>
        <key>Program</key>
        <string>/usr/local/bin/backupkeyfiles.sh</string>
        <key>StartInterval</key>
        <integer>7200</integer>
    </dict>
</plist>

and as for running it:

Code:
Last login: Thu Oct 24 15:56:35 on ttys000
daronbrewood@Darons-Mini-139 URLs % launchctl load ~/Library/LaunchAgents/com.daron.back-up-key-files.plist
/Users/daronbrewood/Library/LaunchAgents/com.daron.back-up-key-files.plist: Invalid property list
daronbrewood@Darons-Mini-139 URLs %

The references I used were:


Back to you :)
 
Both the references you provided show the Label entry, which consists of a key item followed by a value item (string in this case).

The plist you posted is missing a key item before the string item "local.restart", as shown here:
Code:
        <key>Label</key>
        <string>task-lites-off</string>
        <string>local.restart</string>
Every entry in a dict must be a pair: a key item followed by a value item.

I suggest that you start with the example in the stackoverflow article, because that's the one that correctly shows a timed task. It also correctly shows all the required parts. The MakeTechEasier article doesn't show a timed task (in context), although it does show a Label item correctly.

I didn't know why BackupKeyFiles was a key item, but my guess is that you intended it to be the value item associated with the Label key. "local.restart" is the value associated with the Label key in the MakeTechEasier reference, but the way you edited it in the first example posted was wrong. You should have kept the Label key and changed the string value to what you wanted the task name to be.
 
Right, I'll think on this tomorrow. I'm getting completely confused with what I need to change to what now. Better maybe after a nights sleep :)
 
It's close. Just the extra "string", as @chown33 mentioned.

And: don't need to put the script in /usr/local/bin, can keep it local to your account.

Code:
<dict>
    <key>Label</key>
    <string>BackupKeyFiles</string>
    <key>Program</key>
    <string>/usr/local/bin/backupkeyfiles.sh</string>
    <key>RunAtLoad</key>
    <true/>
    <key>StartInterval</key>
    <integer>7200</integer>
</dict>
 
I don't think RunAtLoad is appropriate in this case. None of my timed tasks have it, and they work fine.

If present, I'm pretty sure it will cause the task to run at login. There might be a race condition lurking there, since both iCloud and OneDrive networked services are involved. The specific condition I'm thinking of is that one or both storage services might not be completely ready at the point in time when the agent's script is run.

The reference I consulted (man launchd.plist) also says that RunAtLoad will cause the task to be run "... once at the time the job is loaded." That seems incompatible with repeating timed runs.

And there can be some unexpected interactions between several keys, such as:
 
So is the advice that the '<key>RunAtLoad</key>' line should be removed completely or replaced with something else?

The task does seem to be running okay but then again I've not restarted the Mac Mini at all.
 
Last edited:
As I mentioned in post #10, dict entries must be paired.

Here's the entire plist with the RunAtLoad pair removed.
Code:
<?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>BackupKeyFiles</string>
    <key>Program</key>
    <string>/usr/local/bin/backupkeyfiles.sh</string>
    <key>StartInterval</key>
    <integer>7200</integer>
</dict>
</plist>

The plist may work with RunAtLoad present, but it's not something I'd count on. Sometimes Apple changes how the various parts of a launchd plist behave. The safest course will always be to have no extraneous elements.
 
As I mentioned in post #10, dict entries must be paired.

Thank for that, I see what you mean about the pairing now. I've now changed the plist to:

Code:
<?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.daron.back-up-key-files</string>
    <key>Program</key>
    <string>/usr/local/bin/backupkeyfiles.sh</string>
    <key>StartInterval</key>
    <integer>7200</integer>
</dict>
</plist>

So that the name reflects a better 'run name'. Plus worked out how to stop the original and restart it so I'm learning (albiet slowly) :)

Thanks for all the assistance guys!
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.