Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top redirects URLs like to download links, and you could curl MacUpdate pages for direct download links. Are there any more complete or reliable sources for download links?

How could you automate extracting different types of archives or running installers? DropZone comes with a script that accepts dmg or zip files as input and moves application bundles inside them to /Applications/. Does anyone know a similar script that would work with installers or more file types?

share|improve this question
I keep getting a HTTP 404, Server Not Found – Canadian Luke Jul 20 '12 at 17:38
@Luke I edited the link. – user495470 Jul 20 '12 at 17:41

Take a look at AppFresh. If you enter the applications into your iUseThis profile, you should be able to download them using the semi-automatic download process of that tool. Just select "used but not installed" (or similar) from the sidebar.

As you seem interested in automating handling dmg files, try something like that:

#!/usr/bin/env bash
tempimgfile=$( mktemp img.img) || exit 1
mountpoint=$( mktemp -d img.mnt) || exit 1
curl "$1" > ${tempimgfile} || exit 1
hdiutil attach -mountpoint ${mountpoint} ${tempimgfile} || exit 1
cp -r ${mountpoint}/*.app "/Applications"
hdiutil unmount ${mountpoint}
rm -rf ${mountpoint}
rm -f ${tempimgfile}

Use like this:

$ ./

Of course, it only works for installing new applications and doesn't do any error handling, so use at your own risk. But opening dmg files isn't the actual challenge -- having a comprehensive database of download locations is.

share|improve this answer
And it's almost certainly applescriptable. Google was inconclusive, oddly. – tobylane Mar 18 '11 at 14:09
@tobylane Isn't. At least not 0.8.5 (the latest public preview) – Daniel Beck Mar 18 '11 at 18:10
@Lri There's no standardized format for Mac application downloads, as there is (in a way) for package management software, or e.g. Java's Maven repositories. Therefore there can be no universal solution to this issue (think of the Mariner Software folks that require, or required, you to register for a newsletter before a download. VMware isn't any better). All that's left to do might be to provide better download URLs for iUseThis... – Daniel Beck Mar 18 '11 at 18:44
@Lri Who doesn't? And that last part is more or less solved (although not as stand-alone utility, AFAIK). – Daniel Beck Mar 18 '11 at 18:54
@lri You can copy it out of something like contents/macos/archive.tgz, but that only works for stsndalone programs that don't need to ask for credentials. – tobylane Mar 19 '11 at 10:15
up vote 1 down vote accepted

I ended up hacking together this shell script, but stopped maintaining it since many of the download links at are no longer valid and more applications are now distributed through the App Store. I'm leaving it here for the record anyway.


export uuid1=$(uuidgen) uuid2=$(uuidgen)
export tmp1=/tmp/autoapp$uuid1 tmp2=/tmp/autoapp$uuid2
mkdir -p $tmp1 $tmp2

shopt -s nullglob

trap 'onexit &' EXIT
onexit() {
  for mp in $tmp1/mountpoint-*; do
    hdiutil detach -quiet -force $mp
  rm -rf /tmp/autoapp$uuid1 /tmp/autoapp$uuid2

app() {
  basename="$(basename "$1")"
  ditto "$1" "/Applications/$basename" 2> /dev/null
  echo "Copied $basename to /Applications/"

prefpane() {
  basename="$(basename "$1")"
  ditto "$1" ~/"Library/PreferencePanes/$basename" 2> /dev/null
  echo "Copied $basename to PreferencePanes/"

wdgt() {
  basename="$(basename "$1")"
  ditto "$1" ~/"Library/Widgets/$basename" 2> /dev/null
  echo "Copied $basename to Widgets/" 

pkg() {
  basename="$(basename "$1")"
  sudo installer -pkg "$1" -target /
  if [[ $? != 0 ]]; then
    read -n 1 -p "Open $basename (y/n)? " answer
    [[ "$aswer" == y ]] && open "$f" && exit 1

dmg() {
  basename="$(basename "$1")"
  echo "Mounting $basename"
  yes | hdiutil attach -noverify -nobrowse -mountpoint $mp "$1" > /dev/null
  getfound "$mp" && exit
  echo "Couldn't find an application or package inside $basename"
  exit 1

gettmp() {
  getfound $tmp2 && exit

  found="$(find $tmp2 -depth 1 -name "*.dmg" -print0 2> /dev/null |
  xargs -0 du -s | sort -n | tail -n 1 | cut -f 2)"
  [[ -n "$found" ]] && dmg "$found" && exit

  echo "Couldn't find an application or package"

getfound() {
  found="$(find "$1" -maxdepth 2 -name "*.app" -print0\
  -o -name "*.prefPane" -print0 -o -name "*.pkg" -print0\
  -o -name "*.mpkg" -print0 2> /dev/null |
  xargs -0 du -s | sort -n | tail -n 1 | cut -f 2)"
  if [[ "$found" == *.app ]]; then
    app "$found"
  elif [[ "$found" == *.prefPane ]]; then
    prefpane "$found"
  elif [[ "$found" == *.wdgt ]]; then
    wdgt "$found"
  elif [[ "$found" == *.safariextz ]]; then
    open "$found" && exit
  elif [[ "$found" == *.pkg || "$found" == *.mpkg ]]; then
    pkg "$found"
  exit 1

untradedouble() {
  echo -n "$1" | ruby -e 'require "CGI"
  x = $<.read
  if x =~ /^http:\/\/.*?*?&url=(.+)/
    print CGI.unescape($1)
    print x

[[ $# == 0 ]] && exit
[[ "$1" == "-h" || "$1" == "--help" || "$1" == "-help" ]] && exit

if [[ -e "$@" ]]; then
  [[ -e "$@" ]] && appfile="$@" || exit
elif [[ "$@" =~ "/" || "$@" =~ "." ]]; then
    echo "The file $@ does not exist"
    exit 1

if [[ $download ]]; then
  app2="$(echo "$app" | tr '[:upper:]' '[:lower:]' | sed 's|[^a-z0-9\-]||g')"
  head="$(curl --head --max-time 5 -s -w "%{url_effective}\n" -L "$iut$app2")"
  ok="$(echo "$head" | grep "HTTP/1.[01] [23]..")"
  redirect="$(echo "$head" | tail -n 1 | tr -d '\n')"
  bytes=$(echo "$head" | sed -n 's|Content-Length: ||p' |
  tail -n 1 | tr -d '\r')
  if [[ -z "$redirect" || -z "$ok" ]]; then
    read -n 1 -p "Couldn't find $app. Search with Google (y/n)? " answer
    [[ $answer =~ [y|Y] ]] && open "$google$app2"
  exts=" zip gz rar mpkg dmg safariextz prefPane "
  if [[ "$exts" != *" $ext "* || "$bytes" -le 5000 ]]; then
    redirect="$(untradedouble "$redirect")"
    echo "Redirected to $redirect"
    read -n 1 -p "Open in a browser (y/n)? " answer
    [[ $answer == "y" || $answer == "Y" ]] && open "$redirect"
  echo "Downloading $redirect"
  curl "$redirect" -o "$appfile"

appfile="$(echo -n "$appfile" | sed 's|/$||')"

if [[ "$appfile" == *.app ]]; then
  app "$appfile"
elif [[ "$appfile" == *.prefPane ]]; then
  prefpane "$appfile"
elif [[ "$appfile" == *.wdgt ]]; then
  wdgt "$appfile"
elif [[ "$appfile" == *.safariextz ]]; then
  open "$appfile"
elif [[ "$appfile" == *.zip ]]; then
  unzip -q "$appfile" -d $tmp2
elif [[ "$appfile" == *.tar.gz ]]; then
  tar -xf $appfile -C $tmp2
elif [[ "$appfile" == *.dmg ]]; then
  dmg "$appfile"
elif [[ "$appfile" == *.pkg || "$appfile" == *.mpkg ]]; then
  pkg "$appfile"
  echo "Couldn't process $(basename "$appfile")"
share|improve this answer

Here are a couple other options for automating the installation of .dmg packages:

  1. sprout-wrap
  2. soloist + Chef
  3. Homebrew + Casks

Soloist + sprout-wrap Chef Cookbooks

The first two options allow you to utilize Chef recipes to automate the installation of software onto a Mac (or other OS). The sprout-wrap project from Pivotal Labs is a collection of cookbooks and recipes that provide software installation recipes for Mac OS X. Soloist is a Ruby gem that makes it extremely easy to run chef-solo by providing a single file to contain the run_list of cookbooks/recipes to run and attributes (like variables) that the recipes use.

The homebrew cookbook has a homebrew_cask provider that the sprout-osx-apps cookbook and sprout-osx-base::homebrew recipe use to install homebrew casks via brew cask install. To use the sprout-osx-base::homebrew recipe, simply add the names of casks to install to your node attributes under node[:sprout][:homebrew][:casks] in your soloistrc like in this example.

To keep things simple, just check out the README for sprout-wrap and follow the installation steps. If you want to customize your soloistrc file to choose what to install, you can check out Pivotal's example here or look at my more advanced & customized version here.

If you want an even easier way to get started, check out SoloWizard. Which will generate an auto-install bootstrap script for you to get started with.

Homebrew Casks

If you're not looking for anything as customizable or think Chef/soloist are too complicated... Just start with Homebrew Casks and check if there is an already existing cask formula for your package with brew cask search.

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.