さくらんぼのlambda日記

lambdaちっくなことからゲーム開発までいろいろ書きます。

コマンドの実行結果を文字列に設定する

ちょwまた難しいことをおっしゃる。

とりあえず、プロセスであるとかOSが絡む話はCommon Lispでは規定されていないので、各Common Lisp実装依存になってしまいます。ここでは自分の利用しているSBCLについてのみ考えます。

とりあえず、外部のプログラムを実行する方法を調べてみるとsb-ext:run-programが使えるようです。

さっそく試してみました。

(sb-ext:run-program "/bin/ls" '("/") :output t)
#<SB-IMPL::PROCESS :EXITED 0>

あれ?実行はされてるみたいですが出力が出ません。
slimeでやってるから駄目なのかなと思って普通に端末からsbclを実行してみると。

(sb-ext:run-program "/bin/ls" '("/") :output t)
bin   cdrom  etc   initrd.img  lost+found  mnt  proc  sbin     srv  tmp  var
boot  dev    home  lib         media       opt  root  selinux  sys  usr  vmlinuz
#<SB-IMPL::PROCESS :EXITED 0>

出力されました。

どうやらslime上で出力するには何か一工夫必要そうです。

調査してみると、run-programのキーワード引数:outputに:streamを指定してsb-ext:process-outputの中で実行すれば動作するっぽい。

(with-open-stream (files
                            (sb-ext:process-output
                             (sb-ext:run-program "/bin/ls" '("/" )
                                                 :output :stream)))
           (loop :for line = (read-line files nil nil)
              :while line :do (princ line) (terpri) ))


bin
boot
cdrom
dev
etc
home
initrd.img
lib
lost+found
media
mnt
opt
proc
root
sbin
selinux
srv
sys
tmp
usr
var
vmlinuz
NIL

出来た!

でも出力が出来ただけ。文字列にはまだ出来てないので修正がまだ必要ですね。

と思っていたら、どうやらこの方法は無駄に苦労しているだけだったという罠でした。コメントで教えて頂いた方法の方がずっと良さそうです。

(with-output-to-string (out)
(sb-ext:run-program "/bin/ls" '("/") :output out))

"bin
boot
cdrom
dev
etc
home
initrd.img
lib
lost+found
media
mnt
opt
proc
root
sbin
selinux
srv
sys
tmp
usr
var
vmlinuz
"

こんな感じで文字列にすることは出来ました。ありがとうございます。