Piping stdout and stderr to Preview

A while back, I wrote about how handy it was to redirect a man page into Preview. This allows you to keep the man page open, search it, and generally have a better user experience than struggling with more (or less) to navigate through the information provided there.

man -t apropos | open -fa Preview

Recently, someone asked me about more modern command line interaction, specifically, commands that use --help or similar to provide their documentation. Could that information be opened in Preview as well.

So I put on my thinking hat and set to work. The first command line utility I decided to work with was screencapture because I’ve been using it fairly heavily over the last few days. However, it appears that Apple failed to build in an actual help system beyond man. It was a poor choice to try to use to render but I decided to keep plugging away at it because I wanted to be able to pipe both stdoutand stderr to Preview.

What I came up with looked something like this, all in one line of course:

bash -c "screencapture -? &> 
    /usr/sbin/cupsfilter -i text/plain 
        -D $TMPDIR/previewrendertext.txt 
        2> /dev/null | 
    open -fa Preview"

This all relies on cupsfilter, which can convert a file of text to a printable form, which just happens to be readable by Preview as a PDF.

I’m doing quite a bit of conglomeration, joining the stderr and stdout streams using &> and saving them into my Mac’s $TMPDIR. That file is cleaned up by the -D option from cupsfilter.

I also am removing the incessant debug messages from cupsfilter by redirecting them to /dev/null before opening the print output in Preview.

Please note that I’m still using tcsh/zsh over bash on my main system, so that certainly affects things. Since I needed a little of the bash nuance, I decided to run it all squished as a single -c command. (I’m sure if I spent enough time, I could do it all in csh but I really didn’t want to spend that time.)

As you can see in the previous screenshot, an older utility meant for man output doesn’t really look all that hot shoved into Preview via cupsfilter, especially with line lengths. There’s also no nice groffing and troffing to make everything pretty, the way you get with man:

So how could would this kludge work with a modern command-line app, such as those produced using the Swift Argument Parser (https://github.com/apple/swift-argument-parser)? First, I built a utility that would let me run any command (well, so long as it was properly quoted) without having to type all the details out each time I ran it:

#! /bin/bash

$@ &> $TMPDIR/previewrendertext.txt ; /usr/sbin/cupsfilter -i text/plain -D $TMPDIR/previewrendertext.txt 2> /dev/null | open -fa Preview

This allowed me to call preview "now --help" to redirect the standard help message from my now utility (https://github.com/erica/now)  to Preview. Yeah, originally I wanted to just pipe stuff into it but I couldn’t figure out how to get the stderr and the stdout piped together into a single stream, let alone convert them into a file form because cupsfilter doesn’t know or do pipes.

It’s pretty readable and well-formatted due to the automatic configuration that the Swift Argument Parser provides from my code but it just feels, you know, very very plain.

So I went ahead and tried to see what would happen if I groffed it up a little by passing it through /usr/bin/groff -Tps -mandoc -c instead of using cupsfilter:

bash -c "now --help &> 
    /usr/bin/groff -Tps -mandoc -c 
    $TMPDIR/previewrendertext.txt" | 
    open -fa preview

And it’s…pretty meh. I tried mandoc, mdoc, me, mm, ms, and www formats. They all came out the same, and none of the SAP tabs really worked. I think it looks a lot more “manny” than the straight printout but the indentation really bugged:

I decided to stop at about this point as there’s really a time when further effort just isn’t worth further investment — so I could throw it out there and see if this was of interest to anyone else.

Let me know.


  • 2>&1 should redirect stderr to stdout I think.

  • I don’t think you need the temporary file, do you? cupsfilter appears to be able to read from stdin instead of from a file (even though this is not mentioned in its manpage), and 2>&1 can be used to redirect stderr into stdout without redirecting them both to a file:

    now –help 2>&1 | cupsfilter -i text/plain 2>/dev/null | open -fa Preview

    • I’ll give it a try. As you point out, the usages says to use a file. Thanks!

  • I’ve been using an app called ManOpen for donkey’s years – I’ve copied it from machine to machine for as long as I can remember. The original author’s website isn’t responding, but there’s a fork from a few years ago on GitHub

    Not quite as nifty or versatile as redirecting stdout/stderr to Preview, but I find nothing beats it for viewing man pages.

    Alternatively, another option which doesn’t rely on 3rd party solutions, is to use x-man-page which is built-in, for example open x-man-page://grep.

    The default yellow terminal window can be changed in the Profiles section of Terminal’s preferences.

    • The stdout/err redirect is more for modern utilities that don’t have man pages at all. I’m thinking of asking (or maybe implementing!) the Swift Argument Parser project to include some basic groff-friendly output specifically for rendering, something like utilityname --help --typeset

  • I think I might know what might causing your indentation issue. I got burned my this in the distant past. The grops postprocessor has an option that causes the postscript output to be centered on the page. This is done to allow both letter and A4 paper to be used.

    The more likely problem is the whole nroff/troff/groff world is set up for printing on dead trees. No typesetter in their right mind would ever cram all of their on the left margin by default. You could create a custom pagesize definition as a work-around.

  • I like Bwana for viewing man pages in Safari using man:[command] in the menubar, which still works despite being last updated maybe 10 years ago. You can download the app here: https://www.bruji.com/bwana/ and there is an archie of the repository for the app here: https://bitbucket-archive.softwareheritage.org/projects/br/bruji/bwana.html