Removing old man pages from OS X Leopard

Back in January I posted about Leopard, 'ls -l' and extended attributes. The gist was that my man pages were out of date, so they didn't explain what the @ character represented, in 'ls -l' output.

Some threads on the Apple discussion boards have investigated why the man pages don't get updated. The conclusion is that Leopard installs a lot of gzip-compressed man pages without deleting the corresponding uncompressed man pages. (It may be that this is true only for upgrade installs.) A recommended workaround was to scan through the man page directories with a shell command, re-locating all uncompressed man pages which had corresponding compressed man pages.

I decided to be cowardly in doing this. Here's a Python script which moves each uncompressed man page only if it is older than its corresponding gzipped man page.

The script must be run with superuser privileges, e.g.

$ sudo python

It processes all of the man pages under /usr/share/man, moving old, uncompressed man page files to ~/tmp/old_man_pages.

I would post this to the Apple discussion forums, but it's really overkill. The short shell scripts already posted should work fine, if you ignore the harmless error messages and process each man/man* directory manually.

#!/usr/bin/env python
# encoding: utf-8
"Remove obsolete uncompressed man pages on an OS X Leopard system."

import sys, os, logging

def candidateOldManPages():
    for dirpath, dirnames, filenames in os.walk("."):
        for f in filenames:
            if f.endswith(".gz"):
                fOld = f[:-3]
                if fOld in filenames:
                    yield os.path.join(dirpath, f), os.path.join(dirpath, fOld)

def findOldManPages():
    for p, pOld in candidateOldManPages():
        s = os.stat(p)
            sOld = os.stat(pOld)
        except os.error, info:
            # Some man pages may be broken symbolic links
            logging.warn("Can't stat (%s, %s): %s" % (p, pOld, info))
            if os.path.islink(pOld):
                yield pOld
            if s.st_mtime > sOld.st_mtime:
                yield pOld

def mvOldManPages():
    topDestDir = os.path.expanduser("~/tmp/old_man_pages")
    for relpath in findOldManPages():
        dirname = os.path.dirname(relpath)
        filename = os.path.basename(relpath)

        destDir = os.path.join(topDestDir, dirname)
        if not os.path.exists(destDir):

        logging.debug("mv %s %s" % (relpath, os.path.join(destDir, filename)))
        os.rename(relpath, os.path.join(destDir, filename))

def main():
                        format="%(levelname)s: %(message)s")

if __name__ == "__main__":