10

我试图弄清楚如何使用我开始的一个程序的输出流,RUN-PROGRAM以便它可以用作另一个开始的程序的输入RUN-PROGRAM(即,道德上的,也许是字面上的管道等价物)。我尝试过使用:INPUT,:OUTPUT:WAIT关键字参数的多种组合,但到目前为止,我所遇到的任何事情都没有成效。任何提示都会有所帮助;例如,我将如何ls | grep lisp从 shell 做一些事情?

我的尝试之一是

(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调用中,或仅添加到 for 的调用中grep,并没有解决问题。在这种情况下,该函数将挂起,并且 break withC-c C-c得到一个堆栈跟踪,表明有一个FLET被调用的本地函数(通过定义)SB-UNIX:SELECT已挂起。

4

3 回答 3

10

我在comp.lang.lisp上从 Raymond Toy 那里得到了一个有效的答案。他的解决方案是针对 CMUCL,但它在RUN-PROGRAM密切相关的 SBCL 上具有基本相同的功能,并且稍加改动后它也可以在 CCL 上工作,因为 CCLRUN-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 NIL参数,它也同样有效。RUN-PROGRAMls

于 2010-03-02T14:12:24.977 回答
1

尝试将:wait nil您的论点添加到run-program. 那应该让你的 grep 和你的 ls 在后台运行。照原样,您正在启动 grep 进程,等待该进程完成,然后启动您打算输入 grep 进程的 ls 。唉,因为你在等待 grep 完成,所以你永远不会走那么远。

于 2010-03-01T08:40:13.387 回答
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)
于 2012-07-26T23:45:58.083 回答