Submit Hint Search The Forums LinksStatsPollsHeadlinesRSS
14,000 hints and counting!

A script to shrink and compress disk images easily UNIX
Here is a tcsh shell command which will shrink the unused space of a disk image, then compress it with zlib-level 9.

Features:

  • This method usually results in slightly smaller dmg files than just recompressing them. (gzip is not used here, only hdiutil.)
  • When you open up the resulting dmg you won't see a huge amount of available space (which looks darn silly on a read-only-compressed disk).
  • Filenames with spaces are handled. (Use autocompletion or type a "" before each space in the filename.)
  • The original file is retained, with the suffix ".bak" added.
  • When finished, an "ls" command is automatically performed showing only the new and original dmg files, so you can compare the exact byte sizes.
  • If the Developer Tools "SetFile" command is installed, the type and creator will be set correctly (so the backup file will still have the correct icon and type-association).
Caveats:
  • Requires at least 2x free disk space of the image, depending on how much unused space is inside the dmg. (The disk is copied & converted to a read-write dmg, shrunk, then copied & converted again. There doesn't seem to be a way around this without sacrificing the shrinking step.)
  • Since this is really a shell alias with autocompletion, it works on one file at a time. (It probably wouldn't be too hard to rewrite this into a script).
  • The instructions below are for use with the default tcsh shell. (It shouldn't be too difficult to adapt it for bash.)
[robg adds: I haven't tested this one myself.]

Instructions:
  1. Add the following lines to ~/Library/init/tcsh/aliases.mine (or create the file if not present):
    
    alias dmgcon 'hdiutil convert -format UDRW \!:1 -o \!:1.UDRW \
     && hdiutil resize -sectors `hdiutil resize \!:1.UDRW.dmg | awk \{print\ \$1\}` \!:1.UDRW.dmg \
     && hdiutil convert -imagekey zlib-level=9 -format UDZO \!:1.UDRW.dmg -o \!:1.UDZO \
     && rm \!:1.UDRW.dmg \
     && mv \!:1 \!:1.bak \
     && mv \!:1.UDZO.dmg \!:1 ;\
     [ -f /Developer/Tools/SetFile ] && /Developer/Tools/SetFile -t devr -c ddsk \!:1 ;\
     [ -f /Developer/Tools/SetFile ] && /Developer/Tools/SetFile -t devr -c ddsk \!:1.bak ;\
     ls -alF \!:1.bak \!:1'
    
    Note: The punctuation and spacing are critical! Also notice that the commands do span multiple lines, this is okay because a "\" is used at the end of each line.

  2. Add the following lines to ~/Library/init/tcsh/completions.mine (or create the file if not present):
    
    complete dmgcon 'p/*/f:*.{dmg,img}/'
    
  3. Open a new terminal window for the changes to become active.

Try it out: "cd" to a directory containing a disk image, then type...


dmgcon [tab]
...to see an autocompleted list of .dmg or .img files. Finish the filename, hit return and watch it go.

Enjoy! You can also search for other hdiutil hints at Mac OS X Hints.

    •    
  • Currently 1.00 / 5
  • 1
  • 2
  • 3
  • 4
  • 5
  (3 votes cast)
 
[27,963 views]  

A script to shrink and compress disk images easily | 7 comments | Create New Account
Click here to return to the 'A script to shrink and compress disk images easily' hint
The following comments are owned by whoever posted them. This site is not responsible for what they say.
A script to shrink and compress disk images easily
Authored by: sabi on Mar 10, '03 11:38:35AM
 && hdiutil resize -sectors `hdiutil resize \!:1.UDRW.dmg | awk \{print\ \$1\}` \!:1.UDRW.dmg \
This line can be made simpler:
 && hdiutil resize -sectors min \!:1.UDRW.dmg \
Here's a size comparison:
-rw-------    1 nicholas staff      458970 Mar 10 10:28 ICeCoffEE-1.3.2-awk.dmg
-rw-------    1 nicholas staff      458974 Mar 10 10:25 ICeCoffEE-1.3.2-min.dmg
-rw-------    1 nicholas staff      459134 Mar 10 10:21 ICeCoffEE-1.3.2-orig.dmg
-rw-------    1 nicholas staff      458970 Mar 10 10:30 ICeCoffEE-1.3.2.dmg
The file named "-awk" uses the script as provided, "-min" uses "-size min" instead of "-sectors min", and "-orig" is just gzipped, not resized first.

Interesting hint, thanks! hdiutil is very powerful, just hard to understand at times. Another useful space-saving hint is to create a partition map-less dmg, like this:

hdiutil create "$DMG" -megabytes 5 -ov -layout NONE -fs 'HFS+' -volname "$VOL"
You'll see it mount as /dev/disk#, instead of /dev/disk#s2.

[ Reply to This | # ]
A script to shrink and compress disk images easily
Authored by: carsten on Mar 10, '03 11:50:22AM

Thanks for the simplification tips! I'll have to play with it some more.

BTW I just noticed that while my script handles filenames with spaces, Apple's SetFile utility has trouble. No biggie, you just won't get the proper icon on the bakup file if it has spaces in the filename.



[ Reply to This | # ]
Any Other Scripts Available?
Authored by: jasenko on Mar 10, '03 04:15:26PM

Wow, I didn't know that you can create .dmg using command line. I've been thinking about the best way to make constant backups in the background and to preserve all those bloody resource forks creating dmg is the best solution.
I don't have a clue how to use applescript but I'm pretty handy scripting shells so exploring hdiutil will be my priority for the next few days. In the meantime, does anyone have any scripts for home directory backup or something like that using hdiutil and dmg?



[ Reply to This | # ]
Any Other Scripts Available?
Authored by: gatorparrots on Mar 10, '03 06:07:59PM

#!/bin/sh
#This script will back up your Entourage mail database to a CD
username="`who | grep console | awk '{print $1}'`"
if [ "$username" = "" ]; then
echo "No one logged in via GUI (console)" >&2
exit 1
fi
userhome="`eval echo ~$username`"
date=`date +%Y.%m.%d`
size=`/usr/local/bin/du -sh "$userhome/Documents/Microsoft User Data" | awk ' { print $1 } '`

#Quit Entourage and give it time to write its database to disk
/usr/bin/osascript -l AppleScript -e 'tell Application "Microsoft Entourage" to quit'
/bin/sleep 4

/usr/bin/hdiutil create -fs HFS+ -volname Backup-$date -size $size "$userhome/Desktop/backup.dmg"
/usr/bin/hdiutil mount "$username/Desktop/backup.dmg"
/usr/sbin/disktool -r
echo $date >> /Volumes/Backup-$date/backup.log
/usr/bin/ditto -rsrc -V "$userhome/Documents/Microsoft User Data/Office X Identities/Main Identity/"\
/Volumes/Backup-$date/ >> /Volumes/Backup-$date/backup.log
/usr/bin/hdiutil unmount /Volumes/Backup-$date

#a reminder for those with slot loading drives:
/usr/bin/osascript -l AppleScript -e 'tell Application "Finder" to activate & say "Please insert a blank CDR disc."'
/usr/bin/hdiutil burn "/Users/$username/Desktop/backup.dmg" -noverifyburn -noeject

#Clean up and relaunch Entourage
/bin/rm "$userhome/Desktop/backup.dmg"
/usr/sbin/disktool -r
/usr/bin/osascript -l AppleScript -e 'launch Application "Microsoft Entourage"'



[ Reply to This | # ]
Any Other Scripts Available?
Authored by: jasenko on Mar 10, '03 06:11:53PM

Thanks, this is great script, I will adapt it to better suit my needs. I don't have cd burner on my Mac so I have to transfer the dmg to PC first.



[ Reply to This | # ]
Any Other Scripts Available?
Authored by: Thomas Kaiser on Mar 11, '03 05:44:40AM
> does anyone have any scripts [...] like that using hdiutil and dmg?

I just started to write a simple skript for storing files/folders in disk
images. It's intended to work in the shell as well as in Finder (via
DropScript) with a different 'user interface'. It's a work in progress so
far:

<http://users.phg-online.de/tk/MOSXS/Create_compressed _DiskImage.dmg>

Thomas

[ Reply to This | # ]
A script to shrink and compress disk images easily
Authored by: carsten on Mar 25, '03 07:38:14PM

Update:

I have converted this command alias into a shell script. It still doesn't handle multiple files (please send me patches!).

The most notable improvement to dmgcon is that it now uses a disk image shadow file during the conversion which saves on disk space; this is particularly helpful when working with very large image files. The script has some improved error checking and is also simplified by implementing sabi's hint to take advantage of hdiutil's "-size min" capability instead of invoking awk.

You can download this new dmgcon script from my home page.


#!/bin/sh
#
# dmgcon
#
# version 2.0, 2003-03-25
#
# Shrink Mac OS X disk images to minimum size and convert to UDZO
# (read-only compressed), Mac OS X 10.1 or later.
#
# To use tcsh shell autocompletion with this script, add the
# following line to your completions.mine file:
# complete dmgcon 'p/*/f:*.{dmg,img}/'
# e.g.:
# echo "complete dmgcon 'p/*/f:*.{dmg,img}/'" >> ~/Library/init/tcsh/completions.mine
#
# This 'sh' shell script is public domain.
#
# Last modified:
# 2003-03-25 Carsten Klapp <carstenklapp@yahoo.ca>
#


##
# Usage
##

if [ $# -lt 1 -o $# -gt 2 ]; then
   echo "Usage: `basename $0` file.dmg" 1>&2
   exit 1
fi


##
# Settings & temporary filenames
##

SETFILE="/Developer/Tools/SetFile"
ORIGINALFILE="$1";
TEMPFILE="${ORIGINALFILE}.temp-shadow.dmg"
COMPRESSEDFILE="${ORIGINALFILE}.compressed.dmg"
BACKUPFILE="${ORIGINALFILE}.bak"


##
# Sanity checks
##

# input file exists?
if [ ! -f "${ORIGINALFILE}" ]; then
   echo "Sorry, file '${ORIGINALFILE}' not found." 1>&2
   exit 1
fi

# don't overwrite any of our previous temporary files
errormsg="Sorry, %s '%s' is already present.\nDelete it if you wish to try again.\n"

if [ -f "${TEMPFILE}" ]; then
   printf "${errormsg}", "a temporary file", "${TEMPFILE}"
   exit 1
fi

if [ -f "${COMPRESSEDFILE}" ]; then
   printf "${errormsg}", "a temporary file", "${COMPRESSEDFILE}"
   exit 1
fi

if [ -f "${BACKUPFILE}" ]; then
   printf "${errormsg}", "a backup file", "${BACKUPFILE}"
   exit 1
fi


##
# Main
##

# shrink disk image to the minimum possible size, and use a shadow
# file to save disk space
hdiutil resize -size min "${ORIGINALFILE}" -shadow "${TEMPFILE}"

# convert the disk image into a compressed disk image, but use the
# shrunken shadow file
hdiutil convert -imagekey zlib-level=9 -format UDZO "${ORIGINALFILE}" -shadow "${TEMPFILE}" -o "${COMPRESSEDFILE}"


##
# Cleanup
##

# junk the temp file if it exists
[ -f "${TEMPFILE}" ] && rm "${TEMPFILE}"

# rename the old file if conversion was successful
if [ -f "${COMPRESSEDFILE}" ]; then
   mv "${ORIGINALFILE}" "${BACKUPFILE}"
   mv "${COMPRESSEDFILE}" "${ORIGINALFILE}"

   ##
   # Bonus: set type and creator if developer tools are present
   ##
   if [ -f "${SETFILE}" ]; then
      "${SETFILE}" -t devr -c ddsk "${ORIGINALFILE}"
      "${SETFILE}" -t devr -c ddsk "${BACKUPFILE}"
   fi

   ##
   # Output: display the old and new file sizes
   ##
   ls -alF "${BACKUPFILE}" "${ORIGINALFILE}"
else
   # something went wrong
   echo "Sorry, the disk image '${ORIGINALFILE}' could not be converted."
   echo "Please review the above output for errors."
fi

##
# Done
##


[ Reply to This | # ]