December 29, 2003

Newbie Mac tip: There are several ways to run a script from an icon in the dock:

  • Rename the script so the filename ends with ".command" (e.g. foo.command). Opening the file will cause a Terminal window to open (with its default settings) and run the script in your default shell, followed by an immediate exit. Drag the file to the dock.
  • Or: Associate the script with the Terminal application: select the file in the Finder, get info (File menu, Get Info; or command-i), expand the "Open with" pane, click the dropdown, change "Recommended Applications" to "All Applications" then navigate to /Applications/Utilities/Terminal. Drag the file to the dock.
  • Or: Open a Terminal window, then go to the File menu and select Save As... Enter a name, then change "When opening this file" to execute a command, then enter the command(s) you want it to run. If you execute the script/application in a shell and want the shell to exit when the script/application is done, be sure to add a semi-colon and "exit" at the end of the command, e.g. "/sw/bin/emacs; exit". Click Save. This will create a file with the name you gave followed by .term. Drag this .term file to the dock.

The last option is especially nice because you can configure Terminal to run any command line, not just a script, and you can provide custom Terminal settings to be used only by the script/application. Such as...

Newbie Mac tip: To configure Terminal to close its window when the shell has exited, open a regular Terminal window, go to the application ("Terminal") menu and select Window Settings..., make sure the dropdown says "Shell," then set your preferred "When the shell exits" setting. Be careful: You'll be tempted to hit the "Use Settings as Defaults" button, or at least I was. If you do this, make sure you are editing the window settings of a plain Terminal window and not a Terminal window that was opened to run a ".command" script! If you do the latter and hit the "defaults" button, every Terminal window you open from then on will run the script and immediately exit.

The fix for "all Terminals stuck running your script" is not intuitive (it's not available in any menu option). Browse to your home directory, then find Library/Preferences/com.apple.Terminal.plist. You can edit this file with a text editor, or with /Developer/Applications/Utilities/Property List Editor (installed with the Developer Tools). Find the ExecutionString key and delete it; in a text editor, you'll be removing these two lines:

 <key>ExecutionString</key>
 <string>whatever-script-you-asked-it-to-run; exit</string>

This is the same key you'd add to or remove from a foo.term file to control the running of a script upon Terminal start-up.

Newbie Mac tip: If you want to create an icon that runs an X11 application (such as windowed Emacs, or GnuCash), use this script, which I have named /Users/dan/bin/open-x-and-command (and you might want to copy and paste this, so the browser's wrapping doesn't confuse things):

#!/bin/zsh

sleeptime=0

ps auxwww | grep --silent '/Applications/Utilities/X11.app/Contents/MacOS/X11'
if [[ $? -gt 0 ]] {
  '/Applications/Utilities/X11.app/Contents/MacOS/X11' &
  sleeptime=10
}

if [[ $# -gt 0 ]] {
  sleep $sleeptime
  exec $*;
}

Then, for each application for which you want an icon, you can either:

  • create a appname.term settings file using Terminal to run (for example):
    /Users/dan/bin/open-x-and-command /sw/bin/emacs
  • create a secondary script named appname.command that looks something like this:
    #!/bin/sh
    /Users/dan/bin/open-x-and-command /sw/bin/emacs

Drag the .term or .command file to your dock.

Unfortunately, I don't know how to automatically give the X11 application's window focus from the script, and you can't command-tab through X11 windows (because they all run as a single "X11" application). Anyone?