Clojure Command Line Arguments II
I wrote a small on parsing command line earlier this week. The only comment I got on it from punch was:
I'd like to learn from this post why command-line-args didn't work. What is it, actually, the command-line-args thingy, etc.?
Those are good questions. I didn't know answer to them. As I talk in post I wanted a simple solution to parsing args
and another confusing experience brought me back to the same question, "Why args
behave the way they do and What are *command-line-args*
". I still don't have answer to them. In this post I am documenting two things, for my own better understanding. One around reproducing the issue of jar
not able to work with *command-line-args*
. Second one around limited features of sequence
that are supported by args
Reproducing behaviour of jar
(non)handling of *command-line-args*
We create a new project using lein
:
$ lein new app cli-args
Generating a project called cli-args based on the 'app' template.
$ cd cli-args/
$ lein run
Hello, World!
We edit src/cli_args/core.clj
to print args
and *command-line-args*
cat <<EOF > src/cli_args/core.clj
(ns cli-args.core
(:gen-class))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "Printing args.." args)
(println "Printing *command-line-args*" *command-line-args*))
EOF
$ lein run optional arguments
Now we create jar
using lein uberjar
$ lein uberjar
Compiling cli-args.core
Created target/uberjar/cli-args-0.1.0-SNAPSHOT.jar
Created target/uberjar/cli-args-0.1.0-SNAPSHOT-standalone.jar
$ cd target/uberjar/
$ java -jar cli-args-0.1.0-SNAPSHOT-standalone.jar testing more optional arguments
Printing args.. (testing more optional arguments)
Printing *command-line-args* nil
Clojure is able to handle *command-line-args*
but java
is not. That narrows down the problem and can possibly lead to explanation on why it is happening(Maybe in another post).
Sequence features supported by args
I noticed another anomaly with args
. I was passing couple of arguments and I noticed that it doesn't support get
method.
cat <<EOF > src/cli_args/core.clj
(ns cli-args.core
(:gen-class))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println "first argument" (first args))
(println "second argument" (second args))
(println "third argument" (get args 3)))
EOF
This is what I noticed as I tried different inputs:
$ lein run
first argument nil
second argument nil
third argument nil
$ lein run hello world
first argument hello
second argument world
third argument nil
$ lein run hello world 3rd argument
first argument hello
second argument world
third argument nil
The get
method doesn't work. I printed type
for args
and it is clojure.lang.ArraySeq
. For my case, I "managed" by using last
and that gave me what I wanted. Still, I am running out of options and I would have to either dig deeper to understand args
or fall back to using a library(tools.cli
).