Search code examples
macoscommand-lineterminaldmg.app

How can I silently install a MacOS .app from a dmg, using a single command?


I'm writing an auto update facility for my cross platform application. The updater portion downloads the installer file and executes a shell command to install it. On MacOS our "installer" takes the form of .dmg file. I need to be able to silently mount the disk image, copy/overwrite the contained .app(s) to the destination directory, then unmount the disk image. I am assuming the disk image contains a bundle that can be directly copied to /Applications or elsewhere. There is no sensible way to handle an arbitrary .dmg file as asked before, as its contents cannot be known. Some assumptions must be made.


Solution

  • VOLUME=$(hdiutil attach -nobrowse '[DMG FILE]' |
        tail -n1 | cut -f3-; exit ${PIPESTATUS[0]}) &&
    (rsync -a "$VOLUME"/*.app /Applications/; SYNCED=$?
        (hdiutil detach -force -quiet "$VOLUME" || exit $?) && exit "$SYNCED")
    

    I'll break this down:

    • hdiutil attach -nobrowse '[DMG FILE]' Mount the disk image, but don't show it on the desktop
    • | tail -n1 | cut -f3- Discard the first two tokens of hdiutil's last line output, leaving the remainder, which is the mounted volume
    • VOLUME=$(...; exit ${PIPESTATUS[0]}) Set VOLUME to the output of the above, and set the exit code to that of hdiutil
    • && If the disk image was mounted successfully...
    • rsync -a "$VOLUME"/*.app /Applications/ ...use rsync to copy the .app files to the /Applications directory, while preserving permissions/symlinks/ownership etc.
    • ; SYNCED=$? Store result of rsync operation
    • (hdiutil detach -force -quiet "$VOLUME" force unmount the disk image
    • || exit $?) && "$SYNCED" Exit with hdiutil exit code, or rsync exit code if hdiutil succeeded