April 2011 Entries

Launch shell script silently at login

 

In OSX I needed a shell script to execute at login. There are a few different ways to perform this so I thought it might be helpful to document what your options are. I've switched over to Emacs which typically has a longer startup time than editors such as Vim. This is the shell script we will execute:
#!/bin/zsh
emacs --daemon
Oftentimes Emacs will stay open during an entire user session of the OS, so the sooner I can launch it the better. OSX offers a few different startup options for us. First, we have Login Items available within Account Settings of the System Preference pane. We need to rename the shell script above to end in a .command file extension to allow the Login Items to execute it. This will run at login, however we will be left with a Terminal prompt visible when the script has completed. Preferably we would execute this in the background at user login. OSX manages system and user daemons via a tool called launchd. The interface to launchd is a tool called launchctl which allows for loading and unloading daemons into launchd. XML formatted plist files are used to describe operations loaded into launchctl.
<plist version="1.0">
 <dict>
   <key>Label</key>
   <string>emacs-daemon</string>
   <key>RunAtLoad</key>
   <true />
   <key>Program</key>
   <string>/Users/nickp/bin/scripts/launch-emacs-daemon.sh</string>
  </dict>
</plist>
The above file, emacs-daemon.plist needs to be saved in the ~/Library/LaunchAgents directory. As you can see the xml dictates that the launch-emacs-daemon.sh file should be executed at load, note we no longer need a .command file extension. We will now use launchctl to load our plist file.
launchctl load ~/Library/LaunchAgents/emacs-daemon.plist
To verify that your script executed correctly lets ask launchctl to show us what is running.
launchctl list | grep emacs
You will likely see two entries, each with three columns. Mine looks like this:
148	-	0x100100e80.anonymous.emacs
-	0	emacs-daemon
The first column is the process id, the first row shows the PID of the emacs daemon our shell script spawned. The second line is the emacs-daemon.plist job entry that executed, returning a status code of zero in the second column - success! With this setup, I can launch the emacsclient process which will attach to the daemon server and launch instantly.