112 lines
3.7 KiB
Racket
112 lines
3.7 KiB
Racket
#lang scribble/doc
|
|
@(require scribble/manual
|
|
scheme/cmdline
|
|
"guide-utils.ss")
|
|
|
|
@title[#:tag "scripts"]{Unix Scripts}
|
|
|
|
Under Unix and Mac OS X, a Scheme file can be turned into an
|
|
executable script using the shell's @as-index{@tt{#!}} convention. The
|
|
first two characters of the file must be @litchar{#!}; the next
|
|
character must be either a space or @litchar{/}, 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, and sometimes the space is required.
|
|
|
|
The simplest script format uses an absolute path to a @exec{mzscheme}
|
|
executable followed by a module declaration. For example, if
|
|
@exec{mzscheme} is installed in @filepath{/usr/local/bin}, then a file
|
|
containing the following text acts as a ``hello world'' script:
|
|
|
|
@verbatim[#:indent 2]{
|
|
#! /usr/local/bin/mzscheme
|
|
#lang scheme/base
|
|
"Hello, world!"
|
|
}
|
|
|
|
In particular, if the above is put into a file @filepath{hello} and
|
|
the file is made executable (e.g., with @exec{chmod a+x hello}), then
|
|
typing @exec{./hello} at the shell prompt produces the output
|
|
@tt{"Hello, world!"}.
|
|
|
|
The above script works because the operating system automatically puts
|
|
the path to the script as the argument to the program started by the
|
|
@tt{#!} line, and because @exec{mzscheme} treats a single non-flag
|
|
argument as a file containing a module to run.
|
|
|
|
Instead of specifying a complete path to the @exec{mzscheme}
|
|
executable, a popular alternative is to require that @exec{mzscheme}
|
|
is in the user's command path, and then ``trampoline'' using
|
|
@exec{/usr/bin/env}:
|
|
|
|
@verbatim[#:indent 2]{
|
|
#! /usr/bin/env mzscheme
|
|
#lang scheme/base
|
|
"Hello, world!"
|
|
}
|
|
|
|
In either case, command-line arguments to a script are available via
|
|
@scheme[current-command-line-arguments]:
|
|
|
|
@verbatim[#:indent 2]{
|
|
#! /usr/bin/env mzscheme
|
|
#lang scheme/base
|
|
(printf "Given arguments: ~s\n"
|
|
(current-command-line-arguments))
|
|
}
|
|
|
|
If the name of the script is needed, it is available via
|
|
@scheme[(find-system-path 'run-file)], instead of via
|
|
@scheme[(current-command-line-arguments)].
|
|
|
|
Usually, then best way to handle command-line arguments is to parse
|
|
them using the @scheme[command-line] form provided by
|
|
@schememodname[scheme]. The @scheme[command-line] form extracts
|
|
command-line arguments from @scheme[(current-command-line-arguments)]
|
|
by default:
|
|
|
|
@verbatim[#:indent 2]{
|
|
#! /usr/bin/env mzscheme
|
|
#lang scheme
|
|
|
|
(define verbose? (make-parameter #f))
|
|
|
|
(define greeting
|
|
(command-line
|
|
#:once-each
|
|
[("-v") "Verbose mode" (verbose? #t)]
|
|
#:args
|
|
(str) str))
|
|
|
|
(printf "~a~a\n"
|
|
greeting
|
|
(if (verbose?) " to you, too!" ""))
|
|
}
|
|
|
|
Try running the above script with the @DFlag{help} flag to see what
|
|
command-line arguments are allowed by the script.
|
|
|
|
An even more general trampoline uses @exec{/bin/sh} plus some lines
|
|
that are comments in one language and expressions in the other. This
|
|
trampoline is more complicated, but it provides more control over
|
|
command-line arguments to @scheme{mzscheme}:
|
|
|
|
@verbatim[#:indent 2]|{
|
|
#! /bin/sh
|
|
#|
|
|
exec mzscheme -cu "$0" ${1+"$@"}
|
|
|#
|
|
#lang scheme/base
|
|
(printf "This script started slowly, because the use of\n")
|
|
(printf "bytecode files has been disabled via -c.\n")
|
|
(printf "Given arguments: ~s\n"
|
|
(current-command-line-arguments))
|
|
}|
|
|
|
|
Note that @litchar{#!} starts a line comment in Scheme, and
|
|
@litchar{#|}...@litchar{|#} forms a block comment. Meanwhile,
|
|
@litchar{#} also starts a shell-script comment, while @exec{exec
|
|
mzscheme} aborts the shell script to start @exec{mzscheme}. That way,
|
|
the script file turns out to be valid input to both @exec{/bin/sh} and
|
|
@exec{mzscheme}.
|