20

When I try to load a LaunchAgent plist from launchctl I can't find out how to run a script in the home directory.

My code is:

<?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>ProgramArguments</key>
    <array>
        <string>bash</string>
        <string>~/script.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>Label</key>
    <string>com.tyilo.test</string>
</dict>
</plist>

I have tried both with and without bash and also replacing ~ with $HOME. I have also tried using bash -c without it working.

The error code is:

`com.tyilo.test: bash: ~/script.sh: No such file or directory`
3
  • Try putting the full path e.g. /Users/name/script.sh (Also I would make the script executable and with first line #!/bin/bash and run it directly)
    – mmmmmm
    Jan 13, 2012 at 0:36
  • I can't use the full path as it is to be used on multiple accounts and computers.
    – Tyilo
    Jan 13, 2012 at 0:47
  • 1
    If it is to be used my multiple accounts then you should put it in /usr/local/bin/ instead of making multiple copies of it in each user's $HOME. It would be helpful to know what you are trying to accomplish with this script. It sounds like a job for a LoginHook, IMO.
    – TJ Luoma
    Jan 13, 2012 at 17:14

6 Answers 6

15

EnableGlobbing enables tilde and wildcard expansion for ProgramArguments:

<key>EnableGlobbing</key>
<true/>
<key>ProgramArguments</key>
<array>
    <string>say</string>
    <string>~/*</string>
</array>

It doesn't affect Program or WatchPaths, however tilde expansion works in WatchPaths by default.

5
  • This is way better way of doing this. Is there a place where you can view the documentation for the keys in a LaunchAgent plist?
    – Tyilo
    Mar 8, 2013 at 7:01
  • man launchd.plist. Or see this blog post or my website.
    – Lri
    Mar 8, 2013 at 7:26
  • 1
    This helped me too. Tried in the following Mac OS X Versions: 10.7, 10.8, and 10.9.
    – Dj S
    Mar 24, 2014 at 7:34
  • 7
    Please note: This feature has been removed in Yosemite (Mac OS X 10.10+).
    – alex gray
    Feb 9, 2015 at 23:20
  • Looks like it's not in 10.9.5 either
    – ocodo
    Sep 15, 2015 at 3:06
18

EnableGlobbing doesn't work on OS X Yosemite 10.10. It has been deprecated (ref).

You can see in logs The EnableGlobbing key is no longer respected. Please remove it. (from /var/log/system.log)

The problem is that launchd cwd (current working directory) is /, so you can't use ./ like some people said.

To run a script from your home the simple way is to use (bash|zsh|sh) -c. option. This way you will have the ability to use the tilde ~ or the $HOME variable.

<?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>org.your.stuff</string>
    <key>ProgramArguments</key>
    <array>
      <!-- here is the important thing -->
      <string>zsh</string>
      <string>-c</string>
      <string>~/you/script/in/your/home</string>
    </array>

    <!-- code below is just for the example -->
    <!-- Keep running... -->
    <key>KeepAlive</key>
    <true />
    <!-- ...every day. In sec, 60*60*24 = every day -->
    <key>ThrottleInterval</key>
    <integer>86400</integer>
  </dict>
</plist>
2
  • 2
    I don't think you can use tilde with sh; when Bash is involved as sh, it runs in POSIX compatibility mode, which disables many Bash extensions.
    – tripleee
    Jun 25, 2015 at 8:09
  • ~/ is gobbling so not supported. You can use ./ instead as long as the daemon is saved in the users home library. (~/Library/LaunchAgents)
    – Bruno
    May 23, 2017 at 2:24
10

The most reliable I found of doing this was by using sh and the HOME enviroment variable:

<?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>ProgramArguments</key>
    <array>
        <string>sh</string>
        <string>-c</string>
        <string>"$HOME/script.sh"</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>Label</key>
    <string>com.tyilo.test</string>
</dict>
</plist>

Note: the quotes are required.

1
  • This still works in 2022 on a Mac with MacOS Monterey, which is quite great - since I spent at least an hour of different tests to get a .sh-file running via a .plist in ~/Library/LaunchAgents/ Feb 9, 2022 at 15:28
2

It would be helpful to know why the script needs to be run from the user's home directory. If you need the user's shortname for the script you can get it by assigning it to a variable as in

user=`whoami`

Then use $user in the script.

I would really put the script somewhere other than a home directory, then it's accessible by other users on the same computer. You could use the Shared directory or put the script in /Library/Scripts/

You will have to use the full path for the launchd plist. Also, in your launchd plist you won't need to specify <string>bash</string> as you should have the shebang in the script and it should be executable.

3
  • Specifying bash as the actually command to execute is a good fallback with no real detriment. If he doesn't have the shebang, or forgets to make the script executable (o=rwx), then bash will still invoke / execute the script. Jan 13, 2012 at 17:13
  • 1
    There should already be a variable for the username, such as $USER or $LOGNAME. Also, the usual location for shared Unix scripts would be /usr/local/bin/ (not that you couldn't put them elsewhere, but /usr/local/bin/ will most likely already be in your $PATH).
    – TJ Luoma
    Jan 13, 2012 at 17:23
  • Using whoami is just another method for getting at the same info as $USER or $LOGNAME. I suggested the locations above as I didn't want to presume anything of the questioner. Also, before trying to make the launchd plist work, the script actually needs to be able to run from the CLI.
    – afragen
    Jan 13, 2012 at 17:34
1

Is it executable?

chmod 700 ~/script.sh

in Terminal. Also, I would not use $HOME or ~ but rather the actual path to the file.

<?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.tyilo.test</string>
    <key>ProgramArguments</key>
    <array>
        <string>/path/to/script.sh</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>
1
  • What's the reason for the downvote?
    – TJ Luoma
    Jan 30, 2013 at 15:04
1

If your script is a user agent (and thus located in the library of the Home folder), launchd's current working directory is the Home folder. UNIX refers to the home directory with a period in the path.

So basically, use ./script.sh instead of ~/script.sh. ;-)

3
  • 3
    Nope, the working directory of launchd is actually /, not '~'.
    – Tyilo
    Mar 7, 2013 at 20:05
  • @Tyilo I'm not sure what you mean. If you mean "launchd's working directory is the root, in all cases—even in user mode", please provide a reference. If you mean "launchd uses a slash instead of a tilde", read my post again. By the way, I have several scripts scheduled in launchd and they follow the behaviour I describe. ;-) Mar 7, 2013 at 23:41
  • 1
    @RandyMarch I made a launch agent in ~/Library/LaunchAgents with the arguments: sh, -c, echo $HOME > /Users/Tyilo/launchd_home.txt. When ran the file /Users/Tyilo/launchd_home.txt contained /, not /Users/Tyilo.
    – Tyilo
    Mar 7, 2013 at 23:47

You must log in to answer this question.

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