353

I am wondering if anyone is able to help me out with getting a shell (.sh) program to automatically run whenever I log in to my account on my computer. I am running Mac OS X 10.6.7.

I have a file "Example.sh" that I want to run when I log onto my computer. I do not have a problem running it when I am already logged in, but I want this to run automatically.

MZimmerman6
  • 8,445
  • 10
  • 40
  • 70

3 Answers3

508

Follow this:

  • start Automator.app

  • select Application

  • click Show library in the toolbar (if hidden)

  • add Run shell script (from the Actions/Utilities)

  • copy & paste your script into the window

  • test it

  • save somewhere (for example you can make an Applications folder in your HOME, you will get an your_name.app)

  • go to System Preferences -> Users & Groups -> Login items (or System Preferences -> Accounts -> Login items / depending of your MacOS version)

  • add this app

  • test & done ;)

EDIT:

I've recently earned a "Good answer" badge for this answer. While my solution is simple and working, the cleanest way to run any program or shell script at login time is described in @trisweb's answer, unless, you want interactivity.

With automator solution you can do things like next: automator screenshot login application

so, asking to run a script or quit the app, asking passwords, running other automator workflows at login time, conditionally run applications at login time and so on...

clt60
  • 62,119
  • 17
  • 107
  • 194
  • 2
    @GregMiernicki LOL, good morning... ;) Nearly a year ago added an EDIT to my answer, where telling this too. But, this is a bit simpler for average users, because creating XML (plist) files, is not very user friendly for many users. Anyway - thanx for a comment. ;) – clt60 Nov 06 '13 at 14:49
  • 4
    @GregMiernicki and don't forget, with the Automator solution you can make INTERACTIVE login-scripts - e.g. a script what will ask you for some entry (e.g. additional password or anything like). The world isn't only _black or white_ - at least, it is like a zebra... :) :) – clt60 Nov 06 '13 at 15:25
  • Say, I want to auto run a Python script (basically it will act as a daemon) automatically on start up. Is it possible to run the shell script like you said and invoke the Python script from within? – SexyBeast Aug 11 '14 at 08:19
  • 2
    @Cupidvogel Running an daemon at the login time is exactly the job for the launchd solution - see trisweb's answer. If you can manage a python daemon, youre sure can manage an plist config file where you can manage all aspects of restarts and so on... – clt60 Aug 11 '14 at 15:29
  • Any idea on how to execute the script as root? – nikoskip Mar 21 '16 at 13:00
  • To run a script as root: https://discussions.apple.com/thread/2571517?tstart=0 Example `do shell script "sudo ~/login.sh" with administrator privileges` – nikoskip Mar 23 '16 at 13:04
  • 3
    Kudos for pointing out the other answer as being the cleanest. That should get a good citizenship badge :). – studgeek Jun 06 '16 at 17:51
  • 3
    Amazing answer. Do export PATH=/usr/local/bin:$PATH, at the beginning of the script, if you want to run commands like "composer global update" on system startup. – Leonardo Apr 22 '20 at 12:32
  • 2
    @Leonardo In my case I made a script that updates Python packages and I needed `PATH="/usr/local/opt/gnu-sed/libexec/gnubin:$PATH"` to make it work. So it might vary depending on the needs. Thanks for the tip, btw! – Skaldebane Jun 04 '20 at 14:38
  • 1
    Great and concise answer! One request for change - System Preferences now contains `Users & Groups` instead of `Accounts` – Caleb Hensley Jun 22 '22 at 17:02
  • Now `Users & Groups > Login Items` supports `SH` scripts directly. No need to create this `.app` wrapper. – Alex Barkun Nov 09 '22 at 12:25
  • Simple, details, easy to follow. – azwar_akbar Feb 03 '23 at 16:35
452

tl;dr: use OSX's native process launcher and manager, launchd.

To do so, make a launchctl daemon. You'll have full control over all aspects of the script. You can run once or keep alive as a daemon. In most cases, this is the way to go.

  1. Create a .plist file according to the instructions in the Apple Dev docs here or more detail below.
  2. Place in ~/Library/LaunchAgents
  3. Log in (or run manually via launchctl load [filename.plist])

For more on launchd, the wikipedia article is quite good and describes the system and its advantages over other older systems.


Here's the specific plist file to run a script at login.

Updated 2017/09/25 for OSX El Capitan and newer (credit to José Messias Jr):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
   <key>Label</key>
   <string>com.user.loginscript</string>
   <key>ProgramArguments</key>
   <array><string>/path/to/executable/script.sh</string></array>
   <key>RunAtLoad</key>
   <true/>
</dict>
</plist>

Replace the <string> after the Program key with your desired command (note that any script referenced by that command must be executable: chmod a+x /path/to/executable/script.sh to ensure it is for all users).

Save as ~/Library/LaunchAgents/com.user.loginscript.plist

Run launchctl load ~/Library/LaunchAgents/com.user.loginscript.plist and log out/in to test (or to test directly, run launchctl start com.user.loginscript)

Tail /var/log/system.log for error messages.

The key is that this is a User-specific launchd entry, so it will be run on login for the given user. System-specific launch daemons (placed in /Library/LaunchDaemons) are run on boot.

If you want a script to run on login for all users, I believe LoginHook is your only option, and that's probably the reason it exists.

trisweb
  • 8,814
  • 3
  • 32
  • 22
  • 4
    Yes. FWIW I found this blog on the same technique helpful: http://developernotes.com/archive/2011/04/06/169.aspx – Daniel James Nov 20 '12 at 11:49
  • 8
    You neglect to mention what is dubious about Automator actions, and why they're 'not recommended'. – Mike Campbell Jan 10 '13 at 11:37
  • 4
    Here's a good overview about folder actions vs launchctl: http://apple.stackexchange.com/a/63731/38290 - And another about one of LoginHook's limitations (only one script allowed) - http://superuser.com/a/377401. It's not really that either is a dubious or poor method, but `launchctl` is simply far better in most cases, and gives you more control over all possible aspects of running your script. It's more in the sense of "why use a less capable method when launchd exists?" (Note I've changed the first sentence to indicate that I *personally* do not recommend these for this situation). – trisweb Jan 11 '13 at 14:05
  • 3
    Wondering how you will create LaunchDaemon plist what will run everytime **when the user logging in?**. So, not when the system boots, but **everytime** when the user logging in (try with logout-login cycle). Can you please show **exactly** (not only bla-bla) how to implement the above (by you wrong) automator solution with launchctl? – cajwine Jan 16 '13 at 11:00
  • @cajwine: edited with example as requested. Apologies for the 'bla bla'. – trisweb Jan 17 '13 at 13:51
  • 2
    Please, take my excuses. ;) Now, YES - this is the cleanest solution and the most important part of your answer is: **The key is that this is a User-specific launchd entry, so it will be run on login for the given user.** – cajwine Jan 18 '13 at 11:32
  • 10
    Plist files in _/Library/LaunchAgents/_ are run at login with the id of the logged in user. Plist files in _/Library/LaunchDaemons/_ are run at boot time as root (id can be changed with _User_ key). – bain Apr 25 '15 at 21:24
  • 2
    In my case, in MacOS X El Capitan this example loaded, but it did not started the script. I had to change the .plist file in the Program Key like that: `ProgramArguments /path/to/myscript.sh ` – José Messias Jr Jun 10 '16 at 02:38
  • I made a script that automatically executes instructions described by @trisweb (you only need to pass bash script path) link: https://github.com/myhau/add-startup-script-macos – Michal Fudala Nov 27 '16 at 19:16
  • That just doesn't work… It’s not executing the script. – chitzui Sep 23 '17 at 16:35
  • Hi @chitzui - did you see the updates for the newer OSX versions? I've updated the instructions so all the code is up to date, so please try again and see if it works with the present example. – trisweb Sep 25 '17 at 20:01
  • 3
    Since macOS distinguishes between 'login' and 'login after locking the screen', it's virtually useless for people who lock their screens and want something to run when they login afterwards. – Jan Kyu Peblik Oct 26 '17 at 18:12
  • It worked for me. However, I had to chmod +x the script . – Pierre ALBARÈDE Apr 04 '18 at 13:19
  • 3
    if you get "Service exited with abnormal code: 127" with launchctl but your scripts works correctly when run directly try this: https://stackoverflow.com/questions/18604119/osx-launchd-plist-for-node-forever-process/26389976#26389976 – Scientist1642 Jan 11 '19 at 10:16
  • is this confirmed to work on Mojave? I have created my plist and load it as directed, but no error is returned and it does not show up in "launchctl list", nor does anything when started (no error or message in syslog either) – Riccardo Cossu Mar 14 '19 at 09:44
  • 1
    It’s worth mentioning that the shell script must be executable for this to work. (i.e. `chmod a+x /script/location.sh`) – Brandon Durham Sep 12 '19 at 21:46
  • To run a script as root when you log in to your Mac, [create a login hook](https://support.apple.com/zh-cn/HT2420). – Rockallite Feb 11 '20 at 12:25
  • 1
    To add to @JanKyuPeblik comment, on Catalina it works while logging out then back in, but it does not work when logging in after a reboot. This answer appears to be simply outdated. What probably will work is to disable SIP and re-mount OS (see https://www.launchd.info/ -> Troubleshooting -> bottom of page) – lobi Feb 19 '20 at 21:53
  • Will this work with a single-line command instead of a script? (Say, `echo "hello"` as opposed to `/path/to/script.sh`) – karl Feb 22 '21 at 21:01
  • Let me add that in order to run the login service you first have to load it, then run (or log out and in) and if you make changes you must first unload it before doing step 1 & 2 again. `launchctl load ~/Library/LaunchAgents/com.user.loginscript.plist` , `launchctl start com.user.loginscript`, `launchctl unload ~/Library/LaunchAgents/com.user.loginscript.plist` – Joel Broström Jan 27 '22 at 13:42
  • 1
    I recently created my own startup plist using `launchctl`/`launchd` and it didn't work for me right away. I eventually got it working, wanted to share some tips, there were quite a few issues in my case: * `chmod +x /Users/myusername/Library/LaunchAgents/com.user.mystartupscript.plist` - to make sure the `LaunchAgents` `plist` is executable * `chmod +x /Users/myusername/mystartupscript.sh` - to make sure your script is executable – Kluyg Jul 15 '22 at 19:19
  • 1
    * **This was the root cause in my case**: When `launchd` executes the `Program` command from your `plist` - the `PATH` environment variable is **empty** (crazy, right?). So you have to explicitly set the `PATH` environment variable in the `plist`: ``` EnvironmentVariables PATH /usr/bin:/bin/:$PATH ``` – Kluyg Jul 15 '22 at 19:20
  • 1
    * It's extremely hard to play the "guessing game" when debugging why `launchd` doesn't execute something. By default `launchd` redirects the StdOut/StdErr to `/dev/null`. I suggest you redirect it to a file in `/tmp`. That helped me to debug and fix my startup script: ``` StandardOutPath /tmp/mystartupscript.log StandardErrorPath /tmp/mystartupscript.log ``` – Kluyg Jul 15 '22 at 19:20
  • 1
    * it's also a good idea to set a working directory explicitly for your startup scrip: ``` WorkingDirectory /Users/myusername/ ``` * whenever you make changes to the `launchd` `plist`, you need to force reload it: ``` launchctl unload -w ~/Library/LaunchAgents/com.user.mystartupscript.plist launchctl load -w ~/Library/LaunchAgents/com.user.mystartupscript.plist ``` – Kluyg Jul 15 '22 at 19:20
  • 1
    * `plist` itself is a text XML, with additional rules. Easy to mess up. Always check that it's correct, like this: ``` % plutil ~/Library/LaunchAgents/com.user.mystartupscript.plist /Users/myusername/Library/LaunchAgents/com.user.mystartupscript.plist: OK ``` – Kluyg Jul 15 '22 at 19:20
59
  1. Create a shell script named as login.sh in your $HOME folder.

  2. Paste the following one-line script into Script Editor: do shell script "$HOME/login.sh"

  3. Then save it as an application.

  4. Finally add the application to your login items.

If you want to make the script output visual, you can swap step 2 for this:

tell application "Terminal"
  activate
  do script "$HOME/login.sh"
end tell

If multiple commands are needed something like this can be used:

tell application "Terminal"
  activate
  do script "cd $HOME"
  do script "./login.sh" in window 1
end tell
Joe
  • 879
  • 3
  • 14
  • 37
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 2
    I linked this one, the only thing missing a command line installer ;) – sorin Nov 30 '12 at 16:59
  • 1
    Nice solution. How can I hide the "login" window? I tried ticking in login items. – xgdgsc Jul 15 '13 at 03:15
  • 1
    @xgdgsc: Goto `Go to System Preferences -> Accounts -> Login items` and check hide box for this application. – anubhava Jul 15 '13 at 04:34
  • 1
    @anubhava As I said, I already checked the hide box for this login application. But it still appear and need to be forced to quit when shutting down the computer. – xgdgsc Jul 16 '13 at 11:54
  • 2
    @xgdgsc: Oh ok, did you check `~/Library/LaunchAgents` folder? – anubhava Jul 16 '13 at 12:11
  • @anubhava: I checked and there seems nothing relevant to this login application. I don' t know what it should be like. – xgdgsc Jul 16 '13 at 12:14
  • @xgdgsc: Try searching some keyword in `.plist` files in 3 locations: `/Library/LaunchDaemons/`, `/Library/LaunchAgents` and `~/Library/LaunchAgents` – anubhava Jul 16 '13 at 12:17
  • If you got Permission denied just execute command "chmod u+x login.sh" – user956584 Dec 01 '16 at 04:10
  • 1
    If you want to minimize terminal window automatically then you can add following step after `do script` step: `set miniaturized of window 1 to true` – Leszek Szary Feb 15 '20 at 20:41