12

I want to start up a file with .sh type or .py on mac os x without using root , I searched in google and found launchctl can help me ,

so i read tutorial and do same in tutorial but it not work for me , [i using mac os x 10.9 x64]

My .plist file [run 1.sh file in every 60second] :

<?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.alvin.crontabtest</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Users/paul/Desktop/1.sh</string>
  </array>
  <key>Nice</key>
  <integer>1</integer>
  <key>StartInterval</key>
  <integer>60</integer>
  <key>RunAtLoad</key>
  <true/>
  <key>StandardErrorPath</key>
  <string>/tmp/AlTest1.err</string>
  <key>StandardOutPath</key>
  <string>/tmp/AlTest1.out</string>
</dict>
</plist>

source of 1.sh:

echo '+' >> /Users/paul/Desktop/worked.txt

I put Run.plist in /Users/paul/Run.plist

and run command from terminal :

launchctl load /Users/paul/Run.plist
Launchctl start com.alvin.crontabtest

commands execute without any error but i not see anything in worked.txt

can anyone help me please ?

mklement0
  • 382,024
  • 64
  • 607
  • 775
user3671325
  • 306
  • 2
  • 6
  • 14

2 Answers2

27

To clarify: The OP's .plist file itself was perfectly OK - the problem turned out to be inside the shell script invoked (not shown in the question).

On OS X, using .plist files loaded by CLI launchctl and invoked by daemon manager launchd is the preferred way of scheduling (recurring) tasks (see below for more).

Things to note:

  • The format of launchd .plist files is described in man launchd.plist
  • For a .plist file to be loaded every time the current user logs in, it must be placed in ~/Library/LaunchAgents/ (all-users files must be placed in /Library/LaunchAgent/ - requires root privileges).
  • Specifying output-capture files with keys StandardOutPath and StandardErrorPath means that successive invocations append to the files specified, which means that these files keep growing indefinitely, unless managed externally.
  • Re troubleshooting: @Grady Player's advice applies: launch Console.app and look for com.apple.launchd.peruser entries - a failure to invoke the command specified in the .plist would show there.

@ghoti's answer describes a general Unix alternative to launchd, cron (typically used on Linux):

As for how cron relates to OS X: @ghoti asks:

Any particular reason you don't want to use a normal crontab?

On OS X, man crontab advises (emphasis added):

Although cron(8) and crontab(5) are officially supported under Darwin [OS X], their functionality has been absorbed into launchd(8), which provides a more flexible way of automatically executing commands. See launchctl(1) for more information.

The bottom line is this:

  • If you come from a *nix background, you may be more comfortable with continuing to use cron and crontab, assuming:
    • you're aware of the fact that additional background tasks, scheduled via launchd, may exist.
    • you're aware of cron's limitations and can work with/around them.
  • Otherwise, on OS X:
    • many third-party apps use the native launchd feature and thus specify periodic background tasks via .plist files in /Library/LaunchAgents (for all users) or ~/Library/LaunchAgents (for the current user).
    • If you want to centralize management of background tasks to these locations and/or you want to take advantage of the increased flexibility that launchd provides, go with specifying background tasks via .plist files evaluated by launchd.

Adding simple cron tasks is probably simpler than creating .plist files for launchd, but 3rd-party utilities such as Lingon 3 can help with the latter.

Also, there are subtle differences in how cron tasks are invoked vs. per-user launchd tasks: for instance, the former do not allow user interaction via AppleScript, whereas the latter do.


Case in point re increased flexibility of launchd: the OP, in a follow-up comment, asks for the task to run every 30 seconds:

  • The minimum interval for cron tasks is 60 seconds, necessitating the workaround in @ghoti's answer.

  • By contrast, with the launchd .plist file, changing <key>StartInterval</key><integer>60</integer> to <key>StartInterval</key><integer>30</integer> is enough.

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • @KaushikNayak: Thanks - not sure whether that's a temporary glitch or whether the link truly is dead. To avoid confusion, I've removed it - you can always get the information with `man launchd.plist`. – mklement0 Jun 06 '18 at 15:38
10

Any particular reason you don't want to use a normal crontab?

% echo "* * * * * /Users/paul/Desktop/1.sh" | crontab -

This command should add a cron job that runs once per minute.

NOTE that this command will also replace any crontab that you already have. The crontab - command should be used with caution, as a short-cut.

If you want to edit an existing crontab, so as to avoid obliterating previously set jobs, you can use crontab -e. (If it launches vim and you don't know how to use vim, you can exit by hitting ESC:q!Enter and then go find editor documentation.)

If you want instructions on how to edit crontabs, type man crontab at your shell. If you want syntax information on the crontab file, man 5 crontab will show you that.

Enjoy!


UPDATE: (per comments)

To run your job every 30 seconds requires a simple hack. Cron only runs jobs on a per minute basis, so to run things every 30 seconds, you can have two jobs, one of which has a 30 second delay. For example:

  #Mn Hr Da Mo DW Command
  *   *  *  *  *   /Users/paul/Desktop/1.sh
  *   *  *  *  *   sleep 30; /Users/paul/Desktop/1.sh

Hope this helps.

ghoti
  • 45,319
  • 8
  • 65
  • 104
  • thanks ,but can you get me command same this for do it every 30 second ? or some command i can set seconds, and it will execute also in start up after reset pc ? – user3671325 May 26 '14 at 15:00
  • it's add in my cron job but didn't execute ! after 2minute , i must run any command after echo "* * * * * /Users/paul/Desktop/1.sh" | crontab ? – user3671325 May 26 '14 at 15:10
  • To see what cron jobs are included in your crontab file, run `crontab -l`. The command I gave you, with the dash at the end, will install the quoted output as a crontab, replacing any crontab that is currently in place. For more advanced editing, do try the man pages. Cron should be running by default on Mavericks. (It is on my system.) – ghoti May 26 '14 at 15:20
  • :D in first line i was put #!/usr/bin/sh -_- there is no /usr/bin/sh in mac os x :| :D , thanks , worked fine (Y) – user3671325 May 26 '14 at 15:33
  • 3
    While the `cron`/`crontab` advice is helpful in principle, your advice boils down to this: "You have trouble doing something. Instead of my helping you with that, why don't you try something different?". While this may be appropriate for fundamentally flawed approaches, it is _not_ in the case at hand. Indeed, the OP's problem was not with the `.plist` file for `launchd` at all, but with his/her _script itself_. See my answer for the pros and cons of using `cron` vs. `launchd` on OS X. – mklement0 May 27 '14 at 02:37
  • 2
    PLEASE don't bury `The command I gave you, with the dash at the end, will install the quoted output as a crontab, **replacing any crontab that is currently in place**` (emphasis mine) in a _comment_. By the time a naïve reader has tried the code snippet in your answer, they may have unwittingly wiped out their existing `crontab` file. – mklement0 May 27 '14 at 02:41
  • @mklement0 - *excellent* point about `crontab -`. I've updated my answer accordingly. As for the question of `cron` vs `launchd`, while I don't have a problem with the general principle of launchd, I do feel suspect that the problem with the OP's script might have remain hidden for MUCH longer had the attempt to use cron not been made. .plist files are longer and more complex, and knowledge of launchd is not ubiquitous. Sometimes the simpler approach lets you see flaws more clearly. – ghoti May 27 '14 at 11:52
  • 1
    Thanks for explaining and updating your answer. I do agree that it's helpful to know about `cron` as a simpler - and portable - alternative ; it's indeed easy to get things wrong with `launchd` (though in the case at hand a peek at `Console.app` would have revealed the problem). – mklement0 May 27 '14 at 14:46