Building a Clojure app with a command-line interface?

I just started w/ Clojure (coming from Ruby) and I would like to build an small app with a command-line interface. How do I handle input/output to a CL?

I noticed that there is a clojure.contrib.command-line, but documentation is slim.

http://github.com/richhickey/clojure-contrib/blob/ffa868411cda6c617105b52b4f6f9e0f37ee8c24/src/clojure/contrib/command_line.clj

14329 次浏览

Here is an example of using its with-command-line macro. The following code specifies a trivial class with a main method that does nothing but print out the values of its command line arguments.

(ns cmd-line-demo
(:gen-class)
(:use clojure.contrib.command-line))


(defn -main [& args]
(with-command-line args
"Command line demo"
[[foo "This is the description for foo" 1]
[bar "This is the description for bar" 2]
[boolean? b? "This is a boolean flag."]
remaining]
(println "foo: " foo)
(println "bar: " bar)
(println "boolean?: " boolean?)
(println "remaining: " remaining)))

Compile the class at the REPL:

user> (compile 'cmd-line-demo)
cmd-line-demo

Example usage

1) Executing with no command line arguments will cause the help info to be displayed. The help info can also be displayed with --help or -h flags. Note that the help info is automatically generated from your cmdspec.

$ java -classpath . cmd_line_demo
Command line demo
Options
--foo <arg>    This is the description for foo  [default 1]
--bar <arg>    This is the description for bar  [default 2]
--boolean, -b  This is a boolean flag.

2) Unspecified arguments receive the default value as specified in the cmdspec binding. For example, bar has a default value of 2.

$ java -classpath . cmd_line_demo --foo "changed value"
foo:  changed value
bar:  2
boolean?:  nil
remaining:  []

3) Boolean flags are denoted by the suffix "?" in the cmdspec. Note that the flag itself does not include the "?" as part of its name.

$ java -classpath . cmd_line_demo -boolean
foo:  1
bar:  2
boolean?:  true
remaining:  []

4) Also note that you may specify flag aliases by specifying multiple symbols in the cmdspec. I have done this with the boolean? and b? flags.

5) Finally, I've specified that remaining capture all remaining arguments without associated flags.

$ java -classpath . cmd_line_demo -foo test file1 file2 file3
foo:  test
bar:  2
boolean?:  nil
remaining:  [file1 file2 file3]

I'd like to add that you can do

(apply -main *command-line-args*)

below the (defn -main ...) to make it work in interpreted mode.

Maybe try jark. Jark is a tool to run clojure programs on a persistent JVM. It has some useful command-line utilities.

https://clojars.org/jark

jark ns load file.clj
jark <namespace>.<function> <args>
jark if cli-json <namespace><function> args

The old clojure.contrib.command-line has been replaced with tools.cli.

https://github.com/clojure/tools.cli

tools.cli used to be called clargon. Below are two blog posts that give examples of using tools.cli (simple replace any reference to clargon with tools.cli. Posts are out of date).

This shows a few methods ways, including old clojure.contrib.command-line

Post focusing on Clargon by original author

Long time after the question was raised I can suggest to use docopt libraries when it comes to build CLI interface. There is one for Clojure - docopt.clj

docopt is based on conventions that are used for decades in help messages and man pages for program interface description. Interface description in docopt is such a help message, but formalized

So you can declare your interface and document it in the same time - that is amazing and easy to do.

For more details I recommend to check http://docopt.org/

Also there is a online app to check your interface http://try.docopt.org/

And finally here is my example how the Clojure lib can be used.