nptclのブログ

Common Lisp処理系nptの開発メモです。https://github.com/nptcl/npt

sbclのスクリプトファイル作成

FreeBSD, Linuxsbclスクリプトファイルを作成するメモです。

長々と書きますので、結果だけを先に示します。
スクリプトファイルの1行目には次のように記載すると便利ですね。

#!/usr/bin/env -S sbcl --script

スクリプトファイルの作成

sbclには引数--scriptを指定することにより、スクリプトファイルを読み込むことができます。
つまりは次のように呼び出しを行うことができます。

$ sbcl --script script-file.lisp

しかしこのオプションは、おそらく上記のようにコマンドラインで実行するためのものではなく、 スクリプトファイルに組み込んで使うものだと思います。
問題はこれをどのように記載するかです。

Unix系のOSでは、テキストファイルの1行目を#!で開始することで、 スクリプトに渡す実行ファイルを指定することができます。
開始1byteから#で始める必要があるので、UTF-8のBOMありはエラーになるので注意。

例えば次の通り。

#!/usr/bin/sbcl --script
(format t "Hello~%")

実行してみます。

$ cat > test.sh
#!/usr/bin/sbcl --script
(format t "Hello~%")
^D
$ chmod +x test.sh
$ ./test.sh
Hello

うまく行ったならおめでとう!
でも、上記の書き方だとダメな場合があります。

sbclの場所が違う

Linuxだと/usr/bin/sbclですが、FreeBSDでは/usr/local/bin/sbclとなります。
次のように変更することで動作はします。

#!/usr/local/bin/sbcl --script
(format t "Hello~%")

あるいはsymbolic linkを作成するのでもいいと思います。

# ln -s /usr/local/bin/sbcl /usr/bin/sbcl

しかしこれは問題を解決したと言えるのでしょうか?
実行ファイルの場所が違う問題は、sbclに限らずUnix系ではよく生じる問題です。
一般的には/usr/bin/envを用いて解決します。 envは実行するファイルを環境変数PATHから探し呼び出します。
次のような記載を見たことがある人もいると思います。

#!/usr/bin/env perl
...

今の場合はperlではなくsbclですが、 /usr/bin/usr/local/binPATHに登録されているのであれば、 同じように置き換えることで実行できるかもしれません。

#!/usr/bin/env sbcl --script
(format t "★注意:たぶん失敗する~%")

たぶん失敗すると記載したように、これだとうまく行かないかもしれません。
どうもFreeBSD 6.0までは上記でうまく行けたようなのです。
しかし問題があったためkernelに仕様変更が生じました。
今は次のように、引数-Sを記載するのが正しいとのことです。

#!/usr/bin/env -S sbcl --script
(format t "Hello~%")

これはFreeBSDだけではなくLinuxも正しく動作します。

動作確認を行う場合は、引数のチェックを含めて行った方が良いです。
例えば次のスクリプトファイルを用意します。

#!/usr/bin/env -S sbcl --script
(format t "~S~%" sb-ext:*posix-argv*)

スクリプト名をtest.shとしたときの実行結果を下記に示します。

$ ./test.sh
("sbcl")
$ ./test.sh 10 20 30
("sbcl" "10" "20" "30")

sbclに渡す引数を変更したい

スクリプトで実行するsbclの引数を変更したい場合があります。
例えば--coreを指定したい場合はどうするべきでしょうか。

$ ./test.sh --core /path/to/sbcl.core
("sbcl" "--core" "/path/to/sbcl.core")

たぶん目的とは違った結果になってしまいます。
このように、スクリプトの引数に指定しても何の解決にもなりません。

スクリプトに埋め込む

一つの方法は、スクリプトの1行目に埋め込むことです。
例えば次のようなスクリプトファイルを作成します。

#!/usr/bin/env -S sbcl --core /path/to/sbcl.core --script
(format t "~S~%" sb-ext:*posix-argv*)

これはこれで良いのですが、もし移植性を考えるのであれば、 この方法は使用できないでしょう。

実行するsbclを別のものにする

例えば$HOME/bin/上にsbclというスクリプトを作り、 それをPATHに登録する方法です。
実行するsbclそのものを変更するため、 元々のスクリプトには手を入れる必要がありません。

ユーザーが使用するshellによって手順が変わりますが、 今はbashを使っているものとします。
login時にシステムが自動的に$HOME/binPATHに追加してくれるならよいのですが、 たぶん自分で設定する必要があると思います。
次の手順を実施します。

$ cd $HOME
$ mkdir bin
$ chmod 700 bin
$ vi .bashrc
最終行に下記を追記
export PATH="$HOME/bin:$PATH"

$ vi .bash_profile
次の内容を追記
if [[ -r $HOME/.bashrc ]]; then
  source $HOME/.bashrc
fi

次にsbcl本体のスクリプトファイルを作成します。

$ cd $HOME/bin
$ touch sbcl
$ chmod +x sbcl
$ vi sbcl

次の内容で保存します。

#!/bin/sh
/usr/bin/sbcl --core /path/to/sbcl.core "$@"

一度logoutしてからloginしなおします。
次に起動確認を行います。

$ which sbcl
/home/xxx/bin/sbcl
$ sbcl --version
SBCL 1.4.12

引数のチェックを行ったスクリプトを用意します。

#!/usr/bin/env -S sbcl --script
(format t "~S~%" sb-ext:*posix-argv*)

実行確認を行います。

$ ./test.sh
("/usr/bin/sbcl")
$ ./test.sh 10 20 30
("/usr/bin/sbcl" "10" "20" "30")

なお、.bashrc, .bash_profile, .profileあたりのファイルは、 login時、bash実行時、sshなど外部接続時にて、 読み込まれるファイルが違ったりしますので、 必要に応じてチェックしてみてください。