Scheduling a 1-time future job in OSX?
May 11, 2008 4:17 AM   Subscribe

Mac OS X (Leopard): at(1) replacement?

I need to run a shell script, once, at a specified time in the future (ideally, I'd like to be able to specify "X minutes from now, do this", equivalent to "at now+X minutes").

However, at(1) is broken on OS X (and it's not just because atrun is disabled: at's got some serious time conversion errors) and I can't figure out how to do this via launchd.

Running 10.5.2 if it makes a difference.

Short of using sleep, is there an easy way to queue jobs up for future processing but make it so that the job is only run once, then dequeued/deleted?
posted by aberrant to Computers & Internet (19 answers total) 5 users marked this as a favorite
I think you want to do this with cron. Googling cron and osx should lead you down the correct path, but here are a few top hits anyway [1, 2, 3] and here is a small utility GUI which promises to work although I have no firsthand knowledge of said promise!
posted by sophist at 4:38 AM on May 11, 2008

Agree, cron is the way to do this, and CronniX is the best tool for the job.
posted by dseaton at 5:12 AM on May 11, 2008

Response by poster: Sorry if I wasn't clearer: cron won't do what I want because it's difficult to set it up to schedule a one-time job (how do you automatically remove a cron entry easily)? and the GUI frontends are not useful because I'm scripting the whole thing. I need to programatically submit jobs to run once in the future.
posted by aberrant at 8:19 AM on May 11, 2008

iCal has the option to run a script on an event’s alarm. I don’t know how it will handle an event that would have occurred while the computer was asleep.
posted by ijoshua at 8:47 AM on May 11, 2008

Oh, I missed your reply that your entire workflow is scripted. Perhaps you could use AppleScript to create iCal events with alarms?
posted by ijoshua at 8:48 AM on May 11, 2008

If you use launchd instead of cron, I don't think you can set up a one-time job but it's easy to programatically remove the job - 'launchctl remove jobname'. You could use a script that does whatever you need it to and then removes itself from launchd, or at least disables itself.
posted by dreadpiratesully at 8:53 AM on May 11, 2008

cron has enough granularity that you can specify the job only run once, ever....

as far as removing entries programatically, why not simply overwrite the crontab for the user in question with a new one every time you need to run a new job? have the script dump the cron entry out to a (temp) file, and then call crontab to read that file in?
posted by namewithoutwords at 9:08 AM on May 11, 2008

However, at(1) is broken on OS X

Define "broken"?
posted by Mikey-San at 9:18 AM on May 11, 2008

Response by poster: From the bug report I submitted:

at(1) is queueing jobs with the same jobid (688128) and wildly incorrect times.

sh-3.2# ls -l /usr/bin/at; md5 /usr/bin/at
-r-sr-xr-x 4 root wheel 69552 Dec 10 14:40 /usr/bin/at
MD5 (/usr/bin/at) = 9960f880ca5fe80853ec9adee0494479

One example:
echo "ls" | at now+5 minutes

sh-3.2# date; echo "ls" | at now+5 minutes
Sun May 11 09:11:05 PDT 2008
job 11 at Sun May 11 09:16:00 2008
sh-3.2# at -l
688128 Tue Sep 24 21:01:12 1912


sh-3.2# at -l
11 Sun 11 May 09:16:00 2008

Problem occurs consistently, but the queue time differs.

May be related to the bug in leave(1) (bug ID 5835373).
posted by aberrant at 9:37 AM on May 11, 2008

I think that at works, but it's the BSD at, not the GNU one, so it may not accept all the command line flags that you think it does. Have you read the man page?
posted by sergent at 9:39 AM on May 11, 2008

Hm, I'm probably wrong.
posted by sergent at 9:40 AM on May 11, 2008

Response by poster: Yeah, read the manpage, this should work. Nothing submitted to at(1) is queued at the proper time.
posted by aberrant at 9:43 AM on May 11, 2008

Anyway, you could still write your own cheap version of at in a shell script and run it as a cron job.
posted by sergent at 9:43 AM on May 11, 2008

Best answer: Well, I found the bug. The source code is here. The stupid makefile sets -DDEFAULT_AT_QUEUE to \"a\" instead of \'a\', which breaks everything. You can work around this by adding the '-q a' flag, or by fixing the makefile.
posted by sergent at 9:57 AM on May 11, 2008 [3 favorites]

Response by poster: FANTASTIC. Just updated the bug report. Thanks, sergent!
posted by aberrant at 10:04 AM on May 11, 2008

Wow. AskMe above and beyond.
posted by ctmf at 11:59 AM on May 11, 2008

Ooooh... good catch. DEFAULT_BATCH_QUEUE also needs to be changed then.
posted by sbutler at 12:03 PM on May 11, 2008

Response by poster: Yup. Already added to the bug report. Hopefully this can be fixed.

leave(1) is suffering from possibly similar timing issues, but to the best of my knowledge, it's not using at(1).
posted by aberrant at 1:07 PM on May 11, 2008

Just in case it wasn't clear from my earlier comment, you can use at -q a instead of at to work around the problem. The bug is just in the setting of default for the "-q" flag - the Makefile is setting the default to a string instead of a character, and C just omits a compiler warning for this rather than failing to compile, and Apple evidently doesn't use -Werror.

I'm pretty sure that leave is having a different problem, since it takes no command line flags.
posted by sergent at 10:17 PM on May 11, 2008

« Older Multi-core MySQL fun!   |   does the contraceptive sponge have a flavor? Newer »
This thread is closed to new comments.