[Openmcl-devel] Using ccl as a #! scripting language
John McAleely
john at mcaleely.com
Sun Oct 26 17:16:52 PDT 2008
> I like the idea of setting the arguments into a variable, although I
> suspect that there are likely to be quoting issues if the arguments
> have quote signs or backslashes.
Thank you. You are right about there being quoting issues, so using
the (ccl::command-line-arguments) function seems to be superior, if
undocumented. I suppose I could write an escaping routine in the shell
script, but I'm trying to use more lisp :-) It seems (ccl::command-
line-arguments) still has quoting artefacts in the arguments, but a
determined script could parse these. This seems preferable to my
original which would error in some cases.
> You might also look at SBCL's doc on this, since they have another
> hook that catches exceptions and just prints them and exits. CCL can
> do this with '-b' added to it's command, but it does print out a full
> stack trace.
I was pleased to see I'd written the same function as they cite:
http://www.sbcl.org/manual/Unix_002dstyle-Command-Line-Protocol.html
Which made me feel I was making progress with lisp.
> Also, technically, the SBCL also gets it wrong as well. The dispatch
> macro function should end in (values), otherwise, the string of the
> ignored line is the result of reading the line. It doesn't really
> hurt anything in this case, though.
Thanks. I've fixed mine.
So, taking that all in, here is a new version of the script, which
uses the internal command line arguments function. I admit there are
still quoting issues with the variable I 'declare' in the top line of
the script, if you want the full generality of a lisp symbol, but
those seem worth ignoring for now.
---/usr/local/bin/ccl-script---
#!/bin/bash
# ccl-script
#
# Placed in the public domain by the author
# John McAleely <john at mcaleely.com>
#
# A front end for ccl to be used to create #! executable text scripts on
# unix like operating systems.
# Start your text script with:
# #!/usr/bin/env /path/to/ccl-script *command-line*
#
# *command-line* is defined in the script as a list of the
# command line arguments used to invoke the script
# #! causes the remainder of the line to be ignored.
#
# eg
#
##!/usr/bin/env /path/to/ccl-script *command-line*
#(format t "Hello World called as: ~a" (pop *command-line*))
#(quit)
#
##!/usr/bin/env /path/to/ccl-script *command-line*
#(loop for line = (read-line *standard-input* nil nil)
# while line do (format t "~a~%" line))
#(quit)
# edit this to be your ccl start script of choice (ccl64, openmcl,
etc...)
CCL=ccl
# stash away the name for the global variable that will hold the
# command line
VAR=$1
# Store the name of the script we will load later
SCRIPT=$2
# get rid of the script's paramaters
shift 2
# pass a little bit of read-macro magic in first,
# so that the line #!/usr... in your script is ignored.
# declares #! as a read macro that ignores the remainder of the line.
# Then pass in a debug hook that outputs a simple error instead of the
# interactive debugger. You may prefer to omit this.
# Finally pass in code to create the scripts command line on $VAR from
# the one passed to ccl. Script parameters will be those after the --
$CCL \
-e "(set-dispatch-macro-character #\\# #\\!
#'(lambda (s c1 c2)
(declare (ignore c1 c2))
(read-line s t nil t)
(values)))" \
-e "(setf *debugger-hook*
#'(lambda (condition hook)
(declare (ignore hook))
(format *error-output* \"Error: ~a~%\" condition)
(ccl:quit)))" \
-e "(progn
(defvar $VAR nil)
(let ((script-param
(do ((args (ccl::command-line-arguments) (cdr args)))
((or (null args)
(string= \"--\" (car args)))
(cdr args)))))
(push \"$SCRIPT\" $VAR)
(dolist (x script-param) (push x $VAR))
(setf $VAR (reverse $VAR))))" \
-l "$SCRIPT" -- "$@"
---eof---
More information about the Openmcl-devel
mailing list