I want to run a program by use plist, eg


But the path could be changed in different system, so it would be nice if I can use an environment variable for the plist.


But it seems plist doesn't support environment variable. When I run the /Library/LaunchDaemons/startup.plist, I got error with message:

Invalid or missing Program/ProgramArguments 

Is there anyway to work around?

1 Answer 1


Plists, or property lists, are just a file format for storing serialized objects - for example configurations or similar. The file format specifies how strings are stores, but it doesn't specify anything about higher level details - such as how file names are stored, parsed or otherwise dealt with.

This means that it is not possible to answer your question in general for plists.

The interpretation of $HOME, ~ and environment variables in general in plists are thus application specific. For some programs, it could work - for others it wouldn't. Depends entirely on how that program was made.

UPDATE: You have changed your question to be about LaunchDaemons specifically, and not about plists in general.

For /Library/LaunchDaemons/startup.plist it is not possible to refer directly to the environment variables you mention. They're not parsed and replaced with values by launchd. In addition it probably wouldn't have worked like you thought even if they were, because LaunchDaemons are run by root if nothing else is specified.

What you can do is refer a program in the startup.plist that when run can access the environment and do the variable substitution for you. For example like this:

    <string>exec $HOME/startup.sh</string>
  • Thanks, I just updated my question. It is for LaunchDaemons. Jul 20, 2019 at 20:57
  • @WeijingJayLin I have adjusted the answer.
    – jksoegaard
    Jul 20, 2019 at 21:14
  • 2
    Note that when using bash -c, the command you want to run must be passed as a single <string> (rather than the command and each argument being passed as a separate string, like normal with launchd). This is because the entire command must be passed to bash as a single argument, and then bash will split it into the command, args, etc. The example in this answer shows a simple case of this. Jul 20, 2019 at 22:55
  • 1
    Which value for HOME is used in this case: That of the user the LaunchDaemon is started from, that of the user the daemon runs under (if defined in the plist), or somebody else?
    – nohillside
    Jul 21, 2019 at 8:38
  • That of the user the daemon runs under (could be defined in the plist, otherwise it is root).
    – jksoegaard
    Jul 21, 2019 at 8:40

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .