I have a collection of functions packaged into a Clojure library that I am working on for a bigger application. It occurred to me that many of these Clojure functions would be very useful if I could call them from my bash shell, not just from a REPL. I don’t care about the three second startup time of the JVM, and I don’t want to make a new jar for each little ‘application’ that I am making, since most of these are throw-away scripts or one-liners used for development purposes anyway. How can I start a JVM, load the appropriate libraries, and run a function that I want from the command line or a shell script?

The approach I took was to leverage leiningen to manage dependencies, start up the JVM, load appropriate libraries, and call the appropriate function.

You may be familiar with the acronym REPL, which stands for ‘Read Eval Print Loop”. For this type of task, what we really need is just a ‘Read Eval’ function defined somewhere, since we don’t want to loop. I wrote this stupid function, “Read-eval”, and threw it into one of my libraries.

(defn read-eval
  "Read and evaluate an expression contained in string."
  (eval (read-string string)))

Assuming that I put that into the ‘mylib.util’ namespace, I then run this command in my bash shell:

  $ lein run -m mylib.util/read-eval '(+ 1 2 3)'                     # Add numbers
  $ lein run -m mylib.util/read-eval "(mylib.math/std-dev [1 2 3])"  # variance

If I need to type more than a one-liner, it’s easier just to use ‘load’:

  $ echo "(+ 1 2 3)" > ~/test.clj
  $ lein run -m clojure.core/load-file ~/test.clj

It’s kind of neat how BASH replaces ‘~/’ with the proper home directory before sending it to leiningen.

Anyone got a better way of doing this?