Thursday, March 5, 2009

Clojure Command-Line Arguments

I've recently started using Clojure for my personal projects instead of Common Lisp. I've found it to be similar and different in good ways.

This post is about how to pass command-line arguments to clojure scripts. I'm writing it because I wasn't able to find out how to do so until I stumbled across the patch adding command-line arguments to Clojure.

My setup is for linux (Fedora 10) and includes clojure, clojure-extra, and clojure-contrib. I recommend following Clojure on Ubuntu, even if you aren't using Ubuntu (it works fine with Fedora 10, for instance).

All command-line arguments are stored in the global variable *command-line-args*, which is a list where each argument is a string. Here's what the command-line call needs to look like:

clojure script -- [arg]

where script is the .clj file and each arg is a command-line argument.

For instance,

add-all.clj


(println (reduce + (map read-string *command-line-args*)))

Command-Line


clojure add-all.clj -- 1 9 6

Output


16


Note that the "--" is very important. Without it clojure thinks the args are scripts.

For command-line argument handling, see clojure.contrib.command-line, in the clojure-contrib library. It contains this usage example:

(with-command-line *command-line-args*
"tojs -- Compile ClojureScript to JavaScript"
[[simple? s? "Runs some simple built-in tests"]
[serve "Starts a repl server on the given port" 8081]
[mkboot? "Generates a boot.js file"]
[verbose? v? "Includes extra fn names and comments in js"]
filenames]
(binding [*debug-fn-names* verbose? *debug-comments* verbose?]
(cond
simple? (simple-tests)
serve (start-server (Integer/parseInt serve))
mkboot? (mkboot)
:else (doseq [filename filenames]
(filetojs filename)))))