gosh
のコマンドラインにSchemeプログラムのファイル名が渡された場合、
gosh
はuser
モジュールをカレントモジュールとし、
それ以降のコマンドライン引数のリストをグローバル変数*argv*
に束縛して、
Schemeプログラムをロードします。もしscheme-fileの最初の行が“#!
”で始まって
いたら、その行は無視されます。これにより、Unix系のシステムで実行可能なSchemeスクリプト
を書くことが出来ます。
典型的なGaucheスクリプトの最初の行は次のようなものです。
#!/usr/local/bin/gosh または, #!/usr/bin/env gosh または, #!/bin/sh #| exec gosh -- $0 "$@" |#
後の2つは「シェルトランポリン」テクニックを用いて、gosh
がPATHにあるディレクトリの
どこかにあれば起動できるようにしています。3番目の方法は、
gosh
にいくつかコマンドラインオプションを渡したい時に便利です。
ファイルが正常にロードされたら、gosh
は
userモジュールに ‘main
’ という手続きが定義されているかどうか調べ、
定義されていればそれを呼びます。main
には、スクリプトへの引数のリストが
唯一の引数として渡されます。リストの最初の要素はスクリプトファイル名です。
main
が整数の値を返したら、gosh
はその値を終了ステータスとして終了します。
main
が整数以外の値を返した場合はgosh
は終了ステータス70
(EX_SOFTWARE
)で終了します。このふるまいはSRFI-22と互換です。
main
が定義されていなければgosh
はロード後にそのままステータス0で
終了します。
シェルスクリプトやPerlスクリプトと同じように、スクリプトのボディに直接
実行される式を書くこともできますが、なるべく ‘main
’ を使った方法を
使うことをお薦めします。そうすると、スクリプトをインタプリタにインタラクティブに
ロードしてデバッグすることもできます。
-m
コマンドラインオプションを使えば、user
モジュール以外の
モジュールで定義されたmain
手続きをスクリプトのメイン関数として
呼ぶことができます。Schemeモジュールを、Schemeスクリプトとしても使えるように
したい場合に便利です。
例えば、foo
というSchemeモジュールを書いて、その中で
main
関数を定義しておきます。このmain
関数はexportしないでおきます。
このファイルがモジュールとしてロードされた場合、このmain
関数は
外からは見えないので何もしません。しかし、gosh
に-m foo
オプションを
与えて、このファイルをスクリプトファイルとして指定すれば、ファイルをロードした後に
main
手続きが呼ばれます。その中には、
テストだとかモジュールのサンプルアプリケーションを書いておくことができるでしょう。
R7RSスクリプトに関する註: スクリプトがR7RS Schemeで書かれている場合
(先頭にR7RSのimport
があることで区別されます。
詳しくは3つのimport形式参照)、
スクリプト本体はr7rs.user
へと読み込まれるため、
main
は自動的には呼ばれません。
コマンドライン引数-mr7rs.main
を指定することで、
R7RSスクリプトのmain
を実行できます。
別の方法として、SRFI-22に指定されているように、
スクリプトインタプリタのbasenameがscheme-r7rsであった場合、
スクリプトはR7RSで書かれたSRFI-22形式であると見なされ、
user
モジュールのかわりにr7rs.user
モジュールのmain
が呼ばれます。
そのような別名は自動的にはインストールされませんが、
goshにscheme-r7rsという名前でシンボリックリンクを張るか、
コピーすることができるでしょう。
コマンドライン引数を受け取る標準的な方法は、main
関数の引数としてですが、
他にもコマンドライン引数にアクセスする方法が提供されています。詳しくは
コマンドライン引数を参照してください。
ではいくつか簡単な例を示しましょう。最初の例はUnixのcat(1)
コマンドを模するものです。
エラー処理やコマンドラインオプションの処理は行っていません。
#!/usr/bin/env gosh
(define (main args) ;entry point
(if (null? (cdr args))
(copy-port (current-input-port) (current-output-port))
(for-each (lambda (file)
(call-with-input-file file
(lambda (in)
(copy-port in (current-output-port)))))
(cdr args)))
0)
次のスクリプトは簡単なgrepコマンドです。
#!/usr/bin/env gosh (define (usage program-name) (format (current-error-port) "Usage: ~a regexp file ...\n" program-name) (exit 2)) (define (grep rx port) (with-input-from-port port (lambda () (port-for-each (lambda (line) (when (rxmatch rx line) (format #t "~a:~a: ~a\n" (port-name port) (- (port-current-line port) 1) line))) read-line)))) (define (main args) (if (null? (cdr args)) (usage (car args)) (let ((rx (string->regexp (cadr args)))) (if (null? (cddr args)) (grep rx (current-input-port)) (for-each (lambda (f) (call-with-input-file f (lambda (p) (grep rx p)))) (cddr args))))) 0)
また、gauche.parseopt
- コマンドライン引数の解析を使うと手軽にコマンドラインオプション
を処理することができます。