Lisp Script

Gene Michael Stover

created 2004 April 4
updated 2005 November 15

Copyright © 2004, 2005 Gene Michael Stover. All rights reserved. Permission to copy, store, & view this document unmodified & in its entirety is granted.


Contents

1. Introduction

This article is a How To for using Lisp as a script language from the unix command line. In other words, it's about how to write scripts (a.k.a. programs) in unix like this:

#! /bin/sh
echo Hello, world.
echo Whatever else.

but using Lisp.

1.1 Super Dimension Fortress

If you are a user on Super Dimension Fortress (also known as SDF & Freeshell), & you want to get going as quickly as possible, skip ahead to ``Super Dimension Fortress Quick Start''.

1.2 Non-unix Operating Systems

I'm sure it's possible to use Lisp as a script language in operating systems other than unices, but I don't know how to do it, & this article does not discuss it.

2. How Scripts Work

On a unix, you can tell the program loader to use a particular run-time system in the first line of the program. For example, in this program:

#! /bin/sh
echo Hello, Bourne world!

the ``#! /bin/sh'' tells the loader to use the Bourne shell to execute the lines in the rest of the file.

You might wonder why I put a space after #!. It is not strictly necessary, & in fact it is uncommon. It will work fine on all unices, & it is necessary for backward compatibility with 4.2BSD systems. It's discussed in the info documentation for Gnu's autoconf.


3. Clisp: The Easy Way

Clisp is the easiest Lisp to use as a script language. Clisp knows when it's being used as a script interpreter, so there's almost nothing special you need to do.

Another nice thing about using Clisp as a Lisp script interpreter is that it loads quickly.

Here's an example ``Hello world'' script for Clisp that assumes Clisp is installed as /usr/local/bin/clisp:

#! /usr/local/bin/clisp
(format t "~&Hello, Lispy world!~&")

Right now, you might create a file called ``hello'', copy those two lines into it, run ``chmod 755 hello'', & then type ``./hello''. If you see ``Hello, Lispy world!'', it worked.

You can give Clisp the ``-C'' (that's a capitol C) command line option to tell it to compile the program before it executes it. That'll gain you some performance, though it sometimes dumps ugly warning messages. Here's an example of using the ``-C'' flag:

#! /usr/local/bin/clisp -C

(defun fib (n)
  (if (or (zerop n) (= 1 n))
      1
    (+ (fib (1- n)) (fib (- n 2)))))
(fib 10)

Your Lisp script can access command line arguments in the *ARGS* special variable. *ARGS* will be bound to a list of the strings from the command line. Here's a program that prints the command line arguments so you can see how they appear to your Lisp script:

#! /usr/local/bin/clisp
(format t "~&~S~&" *args*)

Here are some examples of using that program when I've saved it to a file called ``./go'' & ensured that it is executable:

$ cat go
#! /usr/local/bin/clisp
(format t "~&~S~&" *args*)
[gene@palsy /tmp]$ ./go 
NIL
$ ./go a b c
("a" "b" "c")
$ ./go "a b c" 1 2 3
("a b c" "1" "2" "3")
$

Notice that the command line arguments are translated to strings in a Clisp Lisp script, & that you can use double-quotes to force the unix command interpreter to parse the arguments in certain ways, & those behaviours translate to Clisp as you would hope & expect.

As a final example, let's modify the Fibonacci script so that it extracts the number $N$ from the command line. Here it is:

#! /usr/local/bin/clisp -C
;; -*- Mode: Lisp -*-

(defun fib (n)
  (if (or (zerop n) (= 1 n))
      1
    (+ (fib (1- n)) (fib (- n 2)))))

(defvar *n*
  (and (= 1 (length *args*))
       (ignore-errors
         (with-input-from-string (strm (first *args*))
           (read strm)))))

(if (and (integerp *n*) (not (minusp *n*)))
    (format t "~&~D~&" (fib *n*))
  (format t "~&error on the command line~&"))

If I save that script to a file called fib & ensure that it's executable, here are some examples of running it:

$ ./fib -2
error on the command line
$ ./fib asdf
error on the command line
$ ./fib 1
1
$ ./fib 3
3
$ ./fib 4
5
$ ./fib 25
121393
$ ./fib 3.1415927
error on the command line
$

That's all there is to it if you use Clisp & you are willing to gamble that you will never need to move your Lisp scripts to a computer with another kind of Lisp.

On the other hand, if you don't have Clisp or you might need to port your programs to a computer that doesn't have Clisp, keep reading.


4. A More General Solution

Many (most? all?) Lisps other than Clisp are not aware of when they are used as script interpreters, so you need to pull some tricks to make them work as script interpreters.

The trick I chose is to have a wrapper program. It assumes it is being called as a Lisp script interpreter, & it forwards the script to an installed Lisp. The location & type of the Lisp are known at compile-time, so there's no run time spent on locating it or discovering how to invoke it.

The wrapper program copies the Lisp script to a temporary file, then runs the Lisp & tells it to evaluate whatever is in the temporary file. If the Lisp script were very large, there might be a noticeable run time cost of copying it, but in practice, it's fairly small, so the time to copy is negligible.

A programmer who knows C can write such a wrapper program in about a day, but you don't have to write it because this C programmer already did. I call it lisp-script, surprisingly enough.

4.1 Conventions

To help installation programs that try to install applications consisting of Lisp scripts, I suggest that people use a program called ``lisp-script'' to act as a Lisp script language interpreter. It doesn't need to be the lisp-script I wrote.

On a system with Clisp, ``lisp-script'' can be a symlink to the Clisp executable. On systems with other Lisps, lisp-script could be a wrapper program that prepares the script for the installed Lisp to execute.


5. CyberTiggyr lisp-script

CyberTiggyr lisp-script is a wrapper around whatever Lisp is installed on the local computer so that you can use Lisp as a script language. The installation program for lisp-script figures out what Lisp is installed & where, & then it uses conditional compilation to hard-code lisp-script to do whatever it takes to allow the installed Lisp to execute a Lisp script.

When you write programs as Lisp scripts, your installation program needs to locate lisp-script. You also need to take a few measures to ensure your Lisp script will work with whatever Lisp is installed where your Lisp script is used. Other than that, you just write your Lisp script without worrying about which Lisp is installed.

5.1 License

CyberTiggyr lisp-script is free5.1 software. It is released in accordance with the GNU Lesser General Public License. There is a copy of the Lesser General Public License agreement at http://cybertiggyr.com/gene/lscript/lgpl.txt.


5.2 Obatining

The current version of lisp-script is 2. It was released on 14 May 2004.

The distribution archive is available in two formats. You need just one of the archives; either one will do. They are:

  1. http://cybertiggyr.com/gene/lscript/lisp-script-02.cpio.bz2. 127,829 octets.

  2. http://cybertiggyr.com/gene/lscript/lisp-script-02.tar.gz. 207,355 octets.

Remember: You only need one of those files. Either one will do, but I prefer the *.cpio.bz2 version because it's samller & because cpio is more fun to use.

You can browse the source code online at http://cybertiggyr.com/gene/lscript/lisp-script-02.

5.3 Installing

  1. Obtain either of the distribution files. See the links to them in Section 5.2.

  2. If you have the *.cpio.bz2 distribution file, extract it like this: ``bzcat lisp-script-02.cpio.bz2 |cpio -i''.

  3. If you have the *.tar.gz distribution file, extract it like this: ``zcat lisp-script-02.tar.gz |tar xf -''.

  4. ``cd lisp-script-02''

  5. If you have SBCL, Open Lisp (a.k.a. uxlisp), or clisp, & if you want it installed in a directory $D (such as the default /usr/local, or $HOME, type ``./configure -prefix=$D''.

    Otherwise, you have a Lisp other than SBCL, Open Lisp, or clisp, & you'll need to write a *.c file that knows how to execute it. Once you have the file that knows about your Lisp, run ``./configure -prefix=$D''.

  6. ``make all check install''

  7. If the previous command works without errors, you'll have a file called ``$D/bin/lisp-script''. Your Lisp scripts should begin with ``#! $D/bin/lisp-script'', where $D is the directory you specified in the -prefix flag for ./configure.

5.4 Using

Your program's installer should locate lisp-script. I recommend looking in the $PATH, $HOME/BIN, /usr/local/bin, & /usr/bin, in that order. Let's assum your installer stuffs the directory containing lisp-script into an environment variable called $bindir. Then your installer copies your Lisp scripts into place, substituting the value of $bindir for ``@bindir@'' in the Lisp script sources.

The first line of your Lisp scripts should be ``#! @bindir@/lisp-script''. The rest of your Lisp script is just basic Lisp code, but take care to try some portability tricks.

5.5 Portability

CyberTiggyr lisp-script offers a file called script.lisp which helps you write portable Lisp scripts.

One portability obstacle is that different Lisps require different conditions to exit. Clisp exits when it reaches the end of its input file, but you can force an exit by calling EXIT. SBCL & CMUCL will loop forever unless you call QUIT. If you call SCRIPT-EXIT, which is in the script.lisp file, it'll do what is necessary to exit.

In the interest of symmetry, script.lisp also offers a SCRIPT-START function. Call it at or near the beginning of your Lisp script.

There are other portability tricks for Lisp which are beyond the scope of this article. You can read about them in ``Portable Lisp Programming''.

6. Yet Another Solution

Here is another possible solution. I haven't actually tried it.

Instead of writing Lisp scripts, you could load a program into your Lisp & save it as an image file. Then your command line programs would be short scripts that invoked your Lisp, pointed it at the core file, & gave it an initial form to evaluate to start the ball rolling.

I know this could be done with Clisp, SBCL, & CMUCL. I presume it could be done with most or all major Lisp implementations. I expect it would improve start-up times relative to loading your Lisp's generic core file & then loading the Lisp code for your program in a script. It might also be a way to avoid compiler warnings when Lisp loads your program. There may be other advantages to the technique.

The ASDF or MK:DEFSYSTEM Lisp programs might be of use in constructing such installations.


A. Super Dimension Fortress Quick Start

If you're a Lisp programmer on Super Dimension Fortress (SDF, also known as Freeshell), & you want to get your Lisp scripts up & running as soon as possible, here's what you do.

Use your favorite text editor to open a file called hello. Type these lines into it:

#! /arpa/ag/g/gms/bin/lisp-script
(format t "~&~A~&" (list 'hello 'lispy 'world))

Save the file & exit the editor. Then run ``chmod 755 hello''.

Now run your new Lisp script by typing ``./hello''.

A.1 Open Lisp

The Lisp on SDF is Open Lisp. The executable file is /usr/pkg/uxlisp/uxlisp, but you don't need to know that path directly because lisp-script knows about it. (For an explanation of why I recommend using lisp-script instead of running uxlisp directly, read Chapter 4 and Chapter 5.)

The Open Lisp page on the web is http://christian.jullien.free.fr/. It is an ISLISP, not a Common Lisp. If you are already familiar or expert with Lisp, you probably know Common Lisp, & you will find some astonishing behaviours with Open Lisp.

B. Other File Formats

This document is available in multi-file HTML format at http://cybertiggyr.com/gene/lscript/.

This document is available in DVI format at http://cybertiggyr.com/gene/lscript/lscript.dvi.

This document is available in PostScript format at http://cybertiggyr.com/gene/lscript/lscript.ps.

Bibliography

1
a human being.
ISLISP - standards.
http://anubis.dkuug.dk/JTC1/SC22/WG16/, October 1999.

2
Free Software Foundation.
Lesser general public license.
world wide web.
http://www.gnu.org/licenses/licenses.html#LGPL.

3
Gene Michael Stover.
cpio how-to & quick start.
personal web site, March 2002.
http://CyberTiggyr.COM/gene/cpio-howto/.

4
Gene Michael Stover.
Portable lisp programming.
personal web site, April 2004.
http://cybertiggyr.com/gene/plp/.

Gene Michael Stover 2008-04-20