Writing and Running Scripts
Under Unix, a Scheme file can be turned into an executable script
using the shell's #!
convention. The first
two characters of the file must be #!
, and the remainder of
the first line must be a command to execute the script. For some
platforms, the total length of the first line is restricted to 32
characters.
The simplest script format uses an absolute path to a mzscheme executable, followed by -qr. For example, if mzscheme is installed in /usr/plt/bin, then a file containing the following text acts as a ``hello world'' script:
#! /usr/plt/bin/mzscheme -qr (display "Hello, world!") (newline)
In particular, if the above is put into a file hello and the file is made executable (e.g., with chmod a+x hello), then typing ./hello at the shell prompt will produce the output ``Hello, world!''.
Instead of specifying a complete path to the mzscheme executable, an alternative is to require that mzscheme is in the user's command path, and then ``trampoline'' with /bin/sh:
#! /bin/sh #| exec mzscheme -qr "$0" ${1+"$@"} |# (display "Hello, world!") (newline)
The effect is the same, because #
starts a one-line comment to
/bin/sh, but #|
starts a block comment to MzScheme.
Finally, calling mzscheme with exec causes the MzScheme
process to replace the /bin/sh process.
To implement a script inside module
, use -qu instead of
-qr:
#! /usr/plt/bin/mzscheme -qu (module hello mzscheme (display "Hello, world!") (newline))
The -qr command-line flag to MzScheme is an abbreviation for the
-q flag followed by the -r flag. As detailed in
Chapter 17, -q skips the loading of
~/.mzschemerc, while -r suppresses MzScheme's
startup banner, suppresses the read-eval-print loop, and loads the
specified file. In the first example above, the file for -r is
supplied by the shell's #!
handling: it automatically puts
the name of the executed script at the end of the #!
line.
In the second example, the script file name is supplied explicitly
with "$0"
. The -qu flag is similarly an abbreviation for
-q followed by -u, which acts like -r except that
it require
s the script file instead of
ing it.load
If command-line arguments are supplied to a shell script, the shell
attaches them as extra arguments to the script command. Among its
other jobs, the -r or -u flag ensures that the extra
arguments are not interpreted by MzScheme, but instead put into the
parameter as a vector of
strings. For example, the following mock script prints each
command-line argument back on its own line:
current-command-line-arguments
#! /usr/plt/bin/mzscheme -qu (module mock mzscheme (for-each (lambda (arg) (display arg) (newline)) (vector->list (current-command-line-arguments))))
Thus, mock a b c would print ``a'', ``b'', and ``c'', each on its own line. The /bin/sh version is similar:
#! /bin/sh #| exec mzscheme -qu "$0" ${1+"$@"} |# (module mock mzscheme (for-each (lambda (arg) (display arg) (newline)) (vector->list (current-command-line-arguments))))
The ${1+"$@"}
part of the mzscheme command line copies
all shell script arguments to MzScheme for
.current-command-line-arguments
For high-quality scripts, use the cmdline MzLib library to
parse command-line arguments (see Chapter 9
in PLT MzLib: Libraries Manual). The
following hello2 script accepts a --chinese flag to
produce Chinese pinyin output. Due to the built-in functionality of
the command-line
form, the script also accepts a --help
or -h flag that produces detailed help on the available
command-line options:
#! /bin/sh #| exec mzscheme -qu "$0" ${1+"$@"} |# (module hello2 mzscheme (require (lib "cmdline.ss")) (define chinese? #f) (command-line "hello2" (current-command-line-arguments) (once-each [("--chinese") "Chinese output" (set! chinese? #t)])) (display (if chinese? "Nihao, shijie!" "Hello, world!")) (newline))