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 requires 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))