Run file in background from LaunchAgent plist?

1.1k Views Asked by At

I have this 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>updater.Keychain.plist.sh</string>
    <key>ProgramArguments</key>
    <array>
        <string>bash</string>
        <string>-c</string>
        <string>/Users/qwe/Music/meta.sh</string>
        <string>/Users/qwe/Music/seta.sh</string>

    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

The thing is that "meta.sh" is a never-ending script that check every 5 second whether something specific is happening and therefore "seta.sh" is never being run. When doing this in terminal i can simply use the & symbol to make the files run in background but i have tried with the &amp; at the end of the file names but it did not really work. Can anybody please help me? Thanks!!

1

There are 1 best solutions below

4
On BEST ANSWER

chepner's comment is right about the immediate problem: you're passing the script names to bash wrong. After the -c option, bash expects a single argument containing the command to execute (optionally followed by arguments to pass to it, starting with $0). If you want to execute multiple commands, you need to combine them into a single compound command, like /Users/qwe/Music/meta.sh & /Users/qwe/Music/seta.sh.

But I think you're also using launchd wrong. Launchd is really intended to launch processes, and then monitor them; this requires that they stay in the foreground. Things that background themselves out from under launchd tend to confuse it, leading to weird problems. For example, consider the command string I gave above. It runs meta.sh in the background, and seta.sh in the foreground. You said that meta.sh is a long-running process, but I assume seta.sh just does its job and exits? If so, launchd will see that seta.sh (the foreground process) has exited, figure that any subprocesses (meta.sh) are leftover orphans and it should "clean them up", i.e. kill them. Oops, meta.sh is no longer long-running.

If you really just want both meta.sh and seta.sh to be launched, it'd be better to create two separate launchd items (i.e. two .plist files) for them.

If you need to run them together for some reason, probably the best way is to essentially create a small script that runs both of them and then waits for both to exit, and pass that "script" to bash as the parameter to the -c option. Note that this means the entire "script" has to be in a single string in the ProgramArguments array:

<key>ProgramArguments</key>
<array>
    <string>bash</string>
    <string>-c</string>
    <string>/Users/qwe/Music/meta.sh &amp; /Users/qwe/Music/seta.sh; wait</string>
</array>

Another possibility would be to add the AbandonProcessGroup key to the .plist, and not have the "script" wait for background process to finish:

<key>ProgramArguments</key>
<array>
    <string>bash</string>
    <string>-c</string>
    <string>/Users/qwe/Music/meta.sh &amp; /Users/qwe/Music/seta.sh</string>
</array>
<key>AbandonProcessGroup</key>
<true/>

...but this has the disadvantage that launchd doesn't realize there's a background process left over, and under some circumstances it may try to run the job again, resulting in two (or more) background processes...