## Running Command Scripts

If you write a Kawa application, it is convenient to be able to execute it directly (from the command line or clicking an icon, say), without have to explicitly run `kawa` or `java`. On Unix-like systems the easiest way to do this is to write a small shell script that runs your Kawa application.

For modest-sized applications it is convenient if the shell script and the Kawa code can be in the same file. Unix-like systems support a mechanism where a script can specify a program that should execute it. The convention is that the first line of the file should start with the two characters ‘`#!`’ followed by the absolute path of the program that should process (interpret) the script.

(Windows has batch files, which are similar.)

This convention works well for script languages that use ‘`#`’ to indicate the start of a comment, since the interpreter will automatically ignore the line specifying the interpreter filename. Scheme, however, uses ‘`#`’ as a multi-purpose prefix, and Kawa specifically uses ‘`#!`’ as a prefix for various Special named constants such as `#!optional`.

Kawa does recognize the three-character sequence ‘`#!/`’ at the beginning of a file as special, and ignores it. Here is an example:

    #!/usr/local/bin/kawa
    (format #t "The command-line was:~{ ~w~}~%" (command-line))

If you copy this text to a file named `/home/me/bin/scm-echo`, set the execute permission, and make sure it is in your `PATH`, then you can execute it just by naming it on command line:

    $ chmod +x /home/me/bin/scm-echo
    $ PATH=/home/me/bin:$PATH
    $ scm-env a b
    The command-line was: "/home/me/bin/scm-echo" "a" "b"

The system kernel will automatically execute `kawa`, passing it the filename as an argument.

Note that the full path-name of the `kawa` interpreter must be hard-wired into the script. This means you may have to edit the script depending on where Kawa is installed on your system. Another possible problem is that the interpreter must be an actual program, not a shell script. Depending on how you configure and install Kawa, `kawa` can be a real program or a script. You can avoid both problems by the `env` program, available on most modern Unix-like systems:

    #!/usr/bin/env kawa
    (format #t "The command-line was:~{ ~w~}~%" (command-line))

This works the same way, but assumes `kawa` is in the command `PATH`.

### Setting kawa options in the script

If you need to specify extra arguments to `kawa`, you can run arbitrary shell command inside Scheme block comments. Here is an example:

    #!/bin/sh
    #|
    exec kawa out:base=16 out:radix=yes "$0" "$*"
    |#
    (format #t "The command-line is:~{ ~w~}.~%" (command-line))
    (display "It has ")
    (display (apply + (map string-length (command-line))))
    (display " characters.")
    (newline)

The trick is to hide the shell code from Kawa inside a `#|...|#` block-comment. The start of the block comment is a line starting with a `#`, so it is treated as a comment by the shell. You can then invoke `kawa` (or `java` directly) as you prefer, setting up class-path and jars as needed, and passing whatever arguments you want. (The shell replaces the `"$0"` by the name of the script, and replaces the `"$@"` by the remaining arguments passed to the script.) You need to make sure the shell finishes before it reaches the end of the block comment or the Scheme code, which would confuse it. The example uses `exec`, which tells the shell to replace itself by `kawa`; an alternative is to use the shell `exit` command.

If you copy the above file to `/tmp/sch-echo` and make that file executable, you can run it directly:

    $ /tmp/scm-echo "a b" "c d"
    The command-line is: "/tmp/scm-echo" "a b c d".
    It has #x14 characters.

When the Kawa reader sees the initial `#/` it sets the command name to the file name, so it can be used by a future call to `(command-name)`. If you want to override this you can use the `-Dkawa.command.name=`name`` option.

Using comments this way has the advantage that you have the option of running the script “manually” if you prefer:

    $ kawa /tmp/scm-echo out:base=8 "x y"
    The command-line is: "/tmp/scm-echo" "out:base=8" "x y".
    It has 26 characters.

### Other ways to pass options using meta-arg or –script

An argument consisting of just a `\` (backslash) causes Kawa to read the second line looking for options. (Quotes and backslashes work like in the shell.) These replace the backslash in the command line.

This is a less verbose mechanism, but it requires an absolute path to `kawa`, due to shell limitations.

    #!/usr/bin/kawa \
      --scheme --full-tailcalls
    (format #t "The command-line is:~{ ~w~}.~%" (command-line))

In this case the effective command line received by Kawa will be `--scheme`, `--full-tailcalls`, followed by the script filename, followed by other arguments specified when running the script.

The backslash used this way originated in scsh where it is called the meta-arg. (Unlike scsh, Kawa’s `#!` is not a block comment, but a rest-of-line, though the backslash causes the following line to also be skipped.)

An alternative method is to use the `--script2` option, which tells Kawa to execute the script after ignoring the initial two lines. For example:

    #!/bin/sh
    exec kawa --commonlisp out:base=16 --script2 "$0" "$@"
    (setq xx 20) (display xx) (newline)

This is slightly more compact than using block-comments as shown earlier, but it has the disadvantage that you can’t explicitly use `kawa` or `java` to run the script unless you make sure to pass it the `--script2` option.

### Scripts for compiled code

If you compile your Kawa application to class files (or better: a `jar` file), you probably still want to write a small shell script to set things up. Here is one method:

    #!/bin/sh
    export CLASSPATH=/my/path
    exec kawa -Dkawa.command.name="$0" foo "$@"

Using the `kawa` front-end is a convenience, since it automatically sets up the paths for the Kawa classes, and (if enabled) it provides readline support for the default input port.

Setting the `kawa.command.name` property to `"$0"` (the filename used to invoke the script) enables `(command-line`) to use the script name as the command name.

You can invoke `java` directly, which is necessary when running a `jar` file:

    #!/bin/sh
    exec java -cp /path/to/kawa -Dkawa.command.name="$0" foo.jar "$@"