Programming

(Clojure) Shebang Scripting in Clojure

steloflute 2013. 3. 2. 11:49

http://en.wikibooks.org/wiki/Clojure_Programming/Tutorials_and_Tips#Shebang_Scripting_in_Clojure


Shebang Scripting in Clojure

This was tested on Linux only, but should work in other Un*xes.

Put this into command-line-args.clj

#^:shebang '[
exec java -cp "$HOME/src/clj/clojure/clojure.jar" clojure.lang.Script "$0" -- "$@"
]
(prn *command-line-args*)

Make it executable with something like

$ chmod 755 command-line-args.clj

And then run it with parameters.

$ ~/src/clj/lab/command-line-args.clj a b c
("a" "b" "c")

The explanation for this approach is described in this mail on Clojure group.


A more modern version of this approach is to write command-line-args.clj as:

":";exec java -cp "$HOME/path-to-clojure.jar" clojure.main $0 $*

(ns command-line-args)

(defn command-line? []                               
  (.isAbsolute (java.io.File. *file*)))

(defn main [] (println *command-line-args*))

(if (command-line?) (main))

It has a simpler "shebang" line.

(main) is always executed when the script is called from the command-line, even when called with no arguments.

(main) is not executed when command-line-args is used or required by another clojure file.

This method is inspired by this method of emacs scripting and works for the same reasons.


A recent update to Clojure made #! a to-end-of-line comment. Using revision 1106 or later shebang scripting can be done as normal if you have created a clj script, such as those described in Getting started:

#! /usr/bin/env clj

(println "Hello World!")

Otherwise, you can reference java the jar directly, like so:

#! /usr/bin/java -jar clojure.jar clojure.lang.Script

Note: this may not work on all systems, since on some systems only one argument is allowed!


On Windows, a similar approach works for embedding a Clojure script into a batch file:

:x (comment
@echo off
java -cp clojure.jar clojure.main "%~f0" %*
goto :eof
)

(println "Hi!" *command-line-args*)

Here, the first line is seen as a label (because of the initial colon) by cmd.exe, and as a bare keyword followed by the start of a multi-line comment by Clojure. The next lines (to the closing parenthesis) run Java with an appropriate classpath, passing the batch file name ("%~f0") and the command line arguments ("%*") and then exit the batch file (goto eof). The closing parenthesis then terminates the Clojure comment, and Clojure interprets the rest of the file.