κeenのHappy Hacκing Blog | Lispエイリアンの狂想曲

Shellyを使ってCommon LispファイルをExecutableにする

コマンドラインからCommon Lispの関数を実行できる Shellyを使ってCommon Lispファイルを実行形式にしてみました。Shellyは

$ shly + 1 2
3

みたいに関数を実行できます。

モチベーションとしては、 Shellyの作者深町さんがTwitterで「Shellyでloadを使うとスクリプトみたいに実行できる」と発言していたのがきっかけで、Shebangを無視できればUNIX系ではExecutableにできるのでは?と思いついてやってみました。

readしてevalして…とか考えてましたが、loadstreamを渡せるようなので案外簡単にできました。

(in-package :shelly)
(export (defvar argv nil))
(in-package :cl-user)

(defun script (file argv) “Execute a file as script ignoring shebang” (setf shelly:argv argv) (let* ((in (open file :if-does-not-exist :error)) (first-char (read-char in)) (second-char (read-char in))) (cond ((and (char= first-char ##) (char= second-char #!)) (read-line in)) (t (unread-char second-char in) (unread-char first-char in))) (load in) (values)))

コマンドライン引数を受け取るために*argv*という変数を用意してます。

こんなことを~/.shelly/Shellyfileに書いておき、Lispの初期化ファイルに

#+shelly
(load "~/.shelly/Shellyfile")

と書いてます。この~/.shelly/ShellyfileにはShelly向けの関数を溜め込んでいく予定です。

あとは

1
2
3
4
5
#!shly script

(defun hello ()
 (format t "Hello ~a~%" (first shelly:*argv*)))
(hello)

foo.lispに書き込めば

$ chmod u+x foo.lisp
$./foo.lisp κeen
Hello κeen

と実行できます。勿論、

$shly script foo.lisp κeen

としても同じです。一部の処理系ではこのようなことが出来ますが、コマンドライン引数の渡し方とかも処理系依存なのでポータブルに書くなら一つ試してみてはいかがでしょうか。

Written by κeen