如何在Steel Bank Common Lisp中处理输入和输出流?

时间:2010-03-01 01:06:01

标签: lisp common-lisp sbcl

我正在试图弄清楚如何使用我以RUN-PROGRAM开头的一个程序的输出流,因此它可以用作以RUN-PROGRAM开头的另一个程序的输入(即道德也许字面上相当于管道)。我尝试过使用:INPUT:OUTPUT:WAIT个关键字参数的多种组合,但我没有碰到任何内容 到目前为止一直很有成效。任何提示都会有所帮助;例如,我如何从shell中执行类似ls | grep lisp的操作?

我的一次尝试是

(defun piping-test () 
  (let ((grep-process (run-program "/usr/bin/grep" '("lisp") 
                                  :input :stream 
                                  :output :stream))) 
    (unwind-protect 
        (with-open-stream (s (process-input grep-process)) 
          (let ((ls-process (run-program "/bin/ls" '() 
                                        :output s))) 
            (when ls-process 
              (unwind-protect 
                  (with-open-stream (o (process-output grep-process)) 
                   (loop 
                      :for line := (read-line o nil nil) 
                      :while line 
                      :collect line)) 
               (process-close ls-process))))) 
     (when grep-process (process-close grep-process))))) 

在SLIME REPL中运行它会导致一切都挂起,直到我中断 与C-c C-c,所以它显然不是正确的,但我是 不知道如何改变它,所以这是正确的。

编辑::WAIT NIL添加到RUN-PROGRAM个调用,或仅添加grep的调用,并不能解决问题。在这种情况下,函数将挂起,并且与C-c C-c断开会获得一个堆栈跟踪,指示存在已挂起的名为FLET的本地函数(通过SB-UNIX:SELECT定义)。

3 个答案:

答案 0 :(得分:10)

我在comp.lang.lisp得到了Raymond Toy的工作答案。他的解决方案是针对CMUCL的,但它在密切相关的SBCL上使用了基本相同的RUN-PROGRAM函数,并且稍微改变它也适用于CCL,因为CCL的RUN-PROGRAM基本上是一个克隆一个来自CMUCL / SBCL。

秘密就是首先设置ls进程,然后将其输出流作为输入提供给grep进程,如下所示:

(defun piping-test2 () 
  (let ((ls-process (run-program "/bin/ls" '() 
                                 :wait nil 
                                 :output :stream))) 
    (unwind-protect 
        (with-open-stream (s (process-output ls-process)) 
          (let ((grep-process (run-program "/usr/bin/grep" '("lisp") 
                                          :input s 
                                          :output :stream))) 
            (when grep-process 
              (unwind-protect 
                  (with-open-stream (o (process-output grep-process)) 
                    (loop 
                       :for line := (read-line o nil nil) 
                       :while line 
                       :collect line)) 
                (process-close grep-process))))) 
      (when ls-process (process-close ls-process))))) 

我还尝试省略:WAIT NILRUN-PROGRAM的{​​{1}}调用中的ls参数,它的效果也很好。

答案 1 :(得分:1)

尝试将:wait nil添加到run-program的参数中。这应该让你的grep和你的ls在后台运行。你正在启动grep进程,等待完成,然后启动你想要进入grep进程的ls。唉,既然你在等待grep完成,你就永远不会那么远。

答案 2 :(得分:1)

相关地,但也许没有发现你的问题,你可以这样做:

(with-output-to-string (s)
      (ccl:run-program "sh" (list "-c" "ls a/directory/somewhere/*.lisp") :output s)
      s)

(with-output-to-string (s)
      (ccl:run-program "sh" (list "-c" "ls /a/directory/somewhere/*.lisp | wc -l") :output s)
      s)

(with-output-to-string (s)
      (ccl:run-program "ssh" (list "a-user@some-ip" "sh -c ls /a/directory/somewhere/on/remote/server/*.lisp | wc -l") :output s)
      s)

当然,你可以使用

(format nil "ls ~a" directory)

要获得输入,您可以执行以下操作:

(with-output-to-string (out)
      (format t "~%Enter your sudo password:~%")
      (with-input-from-string (s (read))
        (ccl:run-program "ssh" (list *remote* "sudo cat /etc/init.d/nginx")  :input s :output out))
      out)