Mathias Bynens

How to create simple Mac apps from shell scripts

· tagged with Bash, OS X

Basically, a Mac application has a .app extension, but it’s not really a file — it’s a package. You can view the application’s contents by navigating to it in the Finder, right-clicking it and then choosing “Show Package Contents”.

“Show Package Contents” is normally the second item, “Open” being the first.

The internal folder structure may vary between apps, but you can be sure that every Mac app will have a Contents folder with a MacOS subfolder in it. Inside the MacOS directory, there’s an extension-less file with the exact same name as the app itself. This file can be anything really, but in its simplest form it’s a shell script. As it turns out, this folder/file structure is all it takes to create a functional app!

Enter appify

After this discovery, Thomas Aylott came up with a clever “appify” script that allows you to easily create Mac apps from shell scripts. The code looks like this:

#!/bin/bash

APPNAME=${2:-$(basename "$1" ".sh")}
DIR="$APPNAME.app/Contents/MacOS"

if [ -a "$APPNAME.app" ]; then
echo "$PWD/$APPNAME.app already exists :("
exit 1
fi

mkdir -p "$DIR"
cp "$1" "$DIR/$APPNAME"
chmod +x "$DIR/$APPNAME"

echo "$PWD/$APPNAME.app"

Installing and using appify is pretty straightforward if you’re used to working with UNIX. (I’m not, so I had to figure this out.) Here’s how to install it:

  1. Save the script to a directory in your PATH and name it appify (no extension). I chose to put it in /usr/local/bin, which requires root privileges.
  2. Fire up Terminal.app and enter sudo chmod +x /usr/local/bin/appify to make appify executable without root privileges.

After that, you can create apps based on any shell script simply by launching Terminal.app and entering something like this:

$ appify your-shell-script.sh "Your App Name"

Obviously, this would create a stand-alone application named Your App Name.app that executes the your-shell-script.sh script.

After that, you can very easily add a custom icon to the app if you want to.

Adding a custom app icon

  1. Create an .icns file or a 512×512 PNG image with the icon you want, and copy it to the clipboard (⌘ + C). (Alternatively, copy it from an existing app as described in steps 2 and 3.)
  2. Right-click the .app file of which you want to change the icon and select “Get Info” (or select the file and press ⌘ + I).
  3. Select the app icon in the top left corner by clicking it once. It will get a subtle blue outline if you did it right.
  4. Now hit ⌘ + V (paste) to overwrite the default icon with the new one.

Note that this will work for any file or folder, not just .app files.

Examples

Chrome/Chromium bootstrappers

I like to run Chrome/Chromium with some command-line switches or flags enabled. On Windows, you can create a shortcut and set the parameters you want in its properties; on a Mac, you’ll need to launch it from the command line every time. Well, not anymore :)

#!
/Applications/Chromium.app/Contents/MacOS/Chromium --enable-benchmarking --enable-extension-timeline-api&

The & at the end is not a typo; it is there to make sure Chromium is launched in a separate thread. Without the &, Chromium would exit as soon as you quit Terminal.app.

Launch a local web server from a directory

Say you’re working on a project and you want to debug it from a web server. The following shell script will use Python to launch a local web server from a specific directory and open the index page in your default browser of choice. After appifying it, you won’t even need to open the terminal for it anymore.

#!
cd ~/Projects/Foo/
python -m SimpleHTTPServer 8080 &> /dev/null &
open http://localhost:8080/

More?

Needless to say, the possibilities are endless. Just to give another example, you could very easily create an app that minifies all JavaScript and CSS files in a specific folder. Got any nice ideas? Let me know by leaving a comment!

Comments

Thomas Aylott wrote on :

Nice examples.

I’d love to see what else people can come up with. What’d be slick is a droplet that lets you drag a folder into the app to serve that path. Maybe use AppleScript via osascript to give it a simple UI or something.

Fun Times™

Thomas Aylott wrote on :

Platypus actually does something different. It sets the executable to some sort of binary and the includes the script as a resource. It's much slower to load than just a script file in 3 folders.

wrote on :

If you’ve been looking for an easy, automated way to update to the latest Chromium nightly build, look no more!

I just found this script, saved it as chromium-updater.sh, then entered the following command:

appify chromium-updater.sh "Chromium Updater"

Et voilà! Now, all it takes for me to update Chromium is a single click.

Of course, this app won’t be able to give any real visual feedback as to what it’s doing, but if it exits almost immediately it means you already have the latest version installed. If it takes more than a few seconds, you probably don’t and the app is downloading the latest version for ya. (That, or you have a very slow connection, or chromium.org is down.)

If you’re too lazy to build it yourself, you can just download the Chromium Updater app here, complete with a nice icon and everything.

Kevin Grant wrote on :

There is a simpler way to make scripts openable in the Finder, which is to give them the .command extension (.tool also works, I think). This automatically makes them open in a terminal window, which is both more and less convenient, depending on whether or not the script fails. :)

Manuel Villegas wrote on :

Hi, I was pretty seduced by the idea of making Apps out of X11 applications like xdvi, then associating them with .dvi files in Finder. But I somehow can not make it work. My simple write is:

/Applications/Utilities/X11.app/Contents/MacOS/X11 xdvi

…which works when typed in Terminal, but once the app is created, it does nothing. Can somebody help me out? I also downloaded GIMP in the X11 frame, and I don’t get it to have it as a standalone app. I know, for this there is already a Mac Bundle. But for the other X11 applications?

shardbearer wrote on :

I tried this, it opened, didn’t do anything, and immediately stopped responding. Eventually used Automator.

Hawk wrote on :

I tried this, installed it as instructed. But when I did appify test.sh it said “mkdir — permission denied”. So I did it with sudo, but it didn’t create a .app package. I tried again, but this time it said “test.app already exists”… :( What’s going on? Can’t figure it out.

brontosaurusrex wrote on :

Would an app like that take dropped files as arguments for embedded sh/bash script?

Would an app like that auto-launch Terminal to see what’s going on or not?

Ken wrote on :

This appears to be broken. Maybe it doesn’t work with OSX Lion?

In fact, it looks like none of these work anymore… Platypus, Dropscript, Appify… I think Lion broke them all. Even the .command trick no longer works, all that does is open the Terminal without actually running the script.

Romeo wrote on :

Since I use Vim for almost all my files, this kind of approach is quite nice. Is there a method that also assigns icons to the files? Different icons for different extensions would be great. I don’t like it when all the files have the generic white-sheet-of-paper icon.

Eric Larour wrote on :

I’ve been trying the new Appify from Thomas to add Lion support. I’m running on Mac OS X 10.7.2.

My script is a simple:

#!/bin/bash
echo "hello"

When I appify it,

appify script.sh "SCRIPT" 

I get the following:

You can’t open the application SCRIPT because PowerPC applications are no longer supported.

I get nothing from the system.log. Sounds like Mac did something else in the newer versions that breaks the script.

Any feedback welcome,

Eric L.

Hawk wrote on :

I can’t do this. I did mkdir -p ~/Desktop/MyTest.app/Contents/MacOS and saved a MyTest bash script into that folder using nano. Then chmod +x on both the script and the .app directory. The icon is that “invalid app” icon and when I try to launch it, Finder tells me:

You can’t open the application “MyTest” because it’s not supported on this type of Mac.

And then, a split second later:

You can’t open the application MyTest because it is not supported on this type of Mac.

(No quotation marks, and “it is” instead of “it’s”.)

I’m using OS X 10.6.8.

Don wrote on :

I appreciate the ability to copy & paste a custom icon into the selected icon in the new application’s “Get Info” dialog box. But for deployment reasons, I would like to add a .icns icon to the package, and know that it’s there by seeing it in the application’s Resources folder and see an entry for it in the application’s Contents/Info.plist file. I’ve tried adding lines like:

<key>CFBundleIconFile</key>
<string>iconfile</string>

…after the last CFBundle statement in Info.plist file, where iconfile is the name of the .icns icon residing in the Resources folder that I created after the appify.bash run, and into which I copied the .icns icon file. Yet I just don’t seem to be able to make this icon show up in the folder-browser displaying the new application that the newest rev of applify.bash had created. The app runs correctly, but the icon is wrong. I’ve tried copying the application to a new folder, and in this new folder, the displayed icon is still wrong in the folder browser. The icon itself seems to be in good shape; it has all lower-case letters in its name, and the reference for it in Info.plist is thought to be correct. I’ve also tested specifying the filename with or without the icon’s .icns extension.

At this point, I’m out of ideas. I’m probably missing something obvious, but I don’t know what. How does one add a nice .icns icon to a package that the newest rev of applify.bash has just created? Is there some place to look for error messages regarding problems in reading the Info.plist file?

Thanks in advance for your help!

Daniel wrote on :

It appears that the script needs to end in .command to work in Lion. This removes the “You can’t open… type of Mac” errors.

Anonymous wrote on :

After following this post, I was unable to run the .app after using the command appify your-shell-script.sh "Your App Name" in Terminal, using:

#!
cd ~/Projects/Foo/
python -m SimpleHTTPServer 8080 &> /dev/null
open http://localhost:8080/

I receive a prompt saying it was damaged or incomplete.

asdf wrote on :

How do you stop it from bouncing? I have a command that just starts an SSH tunnel and keeps it up. When I start it, it keeps bouncing for like 30 seconds, then when I Ctrl-click it says “Program not responding” and lets me “force quit”. I’d like to tell OS X that it has started up fine, and it can kill it in the normal way if it wants to.

David wrote on :

Thank you! This is exactly what I was looking for! Now I can write scripts for my users to do complicated and/or repetitive tasks, and they can use as a regular app.

Gino wrote on :

This “appify” is quite useless… It’s far easier (and gives fewer problems with scripts) to follow this procedure:

  1. Create your shell script (ex command.sh)
  2. Give it execution permissions (chmod 755 ./command.sh)
  3. Get Info → Open with: → (associate the Terminal app)
  4. Get Info → (put the icon you want on it)

Kind Regards,
Gino

Kwyll wrote on :

Wow, neatest little trick I found in years! Solved my problems with Eclipse on OS X 10.9 in a breeze…

David wrote on :

The problem with Gino’s solution is that you won’t be able to add your script to the Dock. This is why it won’t do for me as I want it to be available from there and not my cluttered desktop. Though, it might work for others.

David wrote on :

Just found a problem with this app – it doesn’t run rsync properly via double click whereas it works fine from a Terminal window. Any idea why?

D3@TH wrote on :

I need help with this. I’m trying to make an app using the .sh extension to run a command like git clone; git submodule update --init; ./make.sh; cp -f but it’s not working.

mahboud wrote on :

Use Automator to turn a shell script into an app. That way, the app can also act as a droplet: drag files onto it and the files will appear to the script as arguments, and are accessible via $1, $2, $3 (or loop through them with for f in "$@").

Don’t waste your time with Appify or Platypus — they are either obsolete, bad-tempered or just not as intuitive and powerful as Automator.

Leave a comment

Comment on “How to create simple Mac apps from shell scripts”

Some Markdown is allowed; HTML isn’t. Keyboard shortcuts are available.

It’s possible to add emphasis to text:

_Emphasize_ some terms. Perhaps you’d rather use **strong emphasis** instead?

Select some text and press + I on Mac or Ctrl + I on Windows to make it italic. For bold text, use + B or Ctrl + B.

To create links:

Here’s an inline link to [Google](http://www.google.com/).

If the link itself is not descriptive enough to tell users where they’re going, you might want to create a link with a title attribute, which will show up on hover:

Here’s a [poorly-named link](http://www.google.com/ "Google").

Use backticks (`) to create an inline <code> span:

In HTML, the `p` element represents a paragraph.

Select some inline text and press + K on Mac or Ctrl + K on Windows to make it a <code> span.

Indent four spaces to create an escaped <pre><code> block:

    printf("goodbye world!"); /* his suicide note
was in C */

Alternatively, you could use triple backtick syntax:

```
printf("goodbye world!"); /* his suicide note
was in C */
```

Select a block of text (more than one line) and press + K on Mac or Ctrl + K on Windows to make it a preformatted <code> block.

Quoting text can be done as follows:

> Lorem iPad dolor sit amet, consectetur Apple adipisicing elit,
> sed do eiusmod incididunt ut labore et dolore magna aliqua Shenzhen.
> Ut enim ad minim veniam, quis nostrud no multi-tasking ullamco laboris
> nisi ut aliquip iPad ex ea commodo consequat.

Select a block of text and press + E on Mac or Ctrl + E on Windows to make it a <blockquote>.