[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

3.3 Schemeスクリプトを書く

goshのコマンドラインにSchemeプログラムのファイル名が渡された場合、 goshはそれ以降のコマンドライン引数のリストをグローバル変数*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' を使った方法を 使うことをお薦めします。そうすると、スクリプトをインタプリタにインタラクティブに ロードしてデバッグすることもできます。

Variable: *argv*

Schemeスクリプト以降のコマンドライン引数のリストは、スクリプトのロードの前に この変数に束縛されます。goshがインタラクティブモードで起動された場合は この変数は()となります。

この変数はSTkと互換性がありますが、他のScheme実装は違った方法を使ってコマンドライン 引数を得ます。ポータブルなスクリプトを書くには、main手続きを使う方法を お薦めします。

Variable: *program-name*

この変数はスクリプトファイル名に束縛されます。インタラクティブモードでは この変数はgosh自身の名前を持っています。

この変数はSTkと互換性がありますが、他の実装は違った方法を使います。

いくつか簡単な例を示します。最初の例は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)
  (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)
      (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 - コマンドライン引数の解析を使うと手軽にコマンドラインオプション を処理することができます。


[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Shiro Kawai on November, 22 2009 using texi2html 1.78.