Launchd run command every minute of a specific hour

launchdplist

On man launchd.plist it says (emphasis mine)

StartCalendarInterval This optional key causes the job to be started every
calendar interval as specified. Missing arguments are considered
to be wildcard
. The semantics are similar to crontab(5) in how
firing dates are specified. Multiple dictionaries may be specified
in an array to schedule multiple calendar intervals.

My plist file is /Users/enricozb/test.plist and contains

<?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.enricozb.test</string>
    <key>ProgramArguments</key>
    <array>
        <string>date</string>
    </array>
    <key>StandardOutPath</key>
    <string>/Users/enricozb/test.txt</string>
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>21</integer>
    </dict>
</dict>
</plist>

Notice that Hour is set to 21, aka, 9PM. Also, notice that the command is just basically date > /Users/enricozb/test.txt. I ran

launchctl load /Users/enricozb/test.plist
launchctl start com.enricozb.test

This fires once right after the launchctl start command, and never again.

I was assuming that since the documentation says that missing arguments are wildcard, that the Minute field would be wildcard too. Why is this not running every minute?

Best Answer

Edit start

You got it all correct except for enclosing your <dict> element inside an <array> element. Your script will run every minute from 21:00 to 21:59 with the following as your StartCalendarInterval key :

    <key>StartCalendarInterval</key>
    <array>
        <dict>
            <key>Hour</key>
            <integer>21</integer>
        </dict>
    </array>

If you wanted your script to run every minute, every hour, every day, every year, the following would be the correct (but certainly not obvious) syntax for that:

    <key>StartCalendarInterval</key>
    <array>
        <dict/>
    </array>

My original answer (below) would also work, but it's clearly much more tedious! OTOH, if one needed every other minute, or certain minutes, it might be useful.

Edit end


<key>StartCalendarInterval</key>
    <array>
        <dict>
            <key>Minute</key>
            <integer>0</integer>
        </dict>
        <dict>
            <key>Minute</key>
            <integer>1</integer>
        </dict>
        <dict>
            <key>Minute</key>
            <integer>2</integer>
        </dict>
        <dict>
            <key>Minute</key>
            <integer>3</integer>
        </dict>
        <dict>
            <key>Minute</key>
            <integer>4</integer>
        </dict>

       ... ad nauseum ...

        <dict>
            <key>Minute</key>
            <integer>59</integer>
        </dict>

    </array>

To answer your question, "Why is this not running every minute?", it's only because you failed to enclose <dict> inside <array>. FWIW, it seems very odd to me also, and WHY it's designed this way is an answer I'd like to hear myself. But then I guess Apple could use the defense that "just because the semantics are similar does not mean the syntax is."