Learning Clojure #9: command-line options
I needed to process some command-line options today in a Clojure app and I dug into the mostly undocumented with-command-line in clojure.contrib.
About the only documentation available is:
Usage: (with-command-line args desc cmdspec & body) Bind locals to command-line args.
That’s great but a little light on examples. :) Fortunately I stumbled on this excellent answer on Stack Overflow which got me 98% of the way there.
Breaking the above params down we have:
- args – the list of incoming args we want to process, such as from a main() call
- desc – the usage description to print with –help
- cmdspec – a list of options and for each a help description and default value
- body – the body to execute in the context of the command-line values
These are all pretty straightforward except for cmdspec which is most easily demonstrated in an example. Just for grins, I implemented something like the classic wc (word count) command. Here’s the relevant part for this example:
(defn -main [& args]
(with-command-line
args
"Usage: wc [-l|-w|-c] [-out out.txt] ..."
[[lines? l? "Count lines" false]
[words? w? "Count words" false]
[chars? c? "Count chars" false]
[out "The output file"]
files]
...implementation... ))
Taking those args again we see the args passed from the command-line, the usage string, and a big vector that is the cmdspec, and finally the body. The cmdspec is a vector of option vectors where each option vector is of the form:
[option [alternate-option*] description [default] ]
The first option defines the local variable that will be set as well. The ? suffix indicates that the option is a boolean option (no value should be passed on the command line). Taking the first option for lines? as an example, the command line will now accept “–lines”, “-lines”, “–l”, and “-l”. The out option is not a boolean and will expect to receive a value on the command line after it. And finally all remaining command line values are put into the files list.
The usage and option strings are used to automatically provide a --help/-h option:
$ java -cp wcc-standalone.jar wcc -h Usage: wc [-l|-w|-c] [-out out.txt] <file>... Options --lines, -l Count lines [default true] --words, -w Count words --chars, -c Count chars --out <arg> The output file
Here we run it in line mode with an output file:
$ java -cp wcc-standalone.jar wcc -l -out lines.txt src/wcc.clj $ cat lines.txt Counted src/wcc.clj: 38
Hope this helps someone down the line…

Hi! My name is Alex Miller and I live in St. Louis. I write code for a living and currently work for
It does help. I didn’t know about this macro, it helps to make a command line program less of a hussle in detecting arguments and options.
Nice work. You should submit a patch to improve the docstring: future Clojurians will thank you!
@Craig: Great idea! I’ll do it.