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

发布于 2024-08-23 19:56:19 字数 1424 浏览 4 评论 0原文

我试图弄清楚如何使用以 RUN-PROGRAM 启动的一个程序的输出流,以便它可以用作以 RUN-PROGRAM 启动的另一个程序的输入code>(即道德上或者字面意义上的管道的等价物)。我尝试使用 :INPUT:OUTPUT:WAIT 关键字参数的多种组合,但没有任何效果 到目前为止一直富有成效。任何提示都会有帮助;例如,我将如何去做类似 ls | 的事情?从 shell 中运行 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 中运行它会导致一切都挂起,直到我崩溃 与 Cc Cc,所以这显然不是正确的事情,但我 不知道如何改变它,所以这是正确的事情。

编辑::WAIT NIL添加到两个RUN-PROGRAM调用中,或仅添加到grep调用中,不会别耍花招。在这种情况下,该函数将挂起,并使用 Cc Cc 中断会获取堆栈跟踪,表明有一个名为 SB-UNIX 的本地函数(通过 FLET 定义) :SELECT 已挂起。

I'm trying to figure out how to use the output stream of one program I start with RUN-PROGRAM so it can be used as the input of another program started with RUN-PROGRAM (i.e., the moral and perhaps literal equivalent of piping). I've tried using a number of combinations of the :INPUT, :OUTPUT and :WAIT keyword arguments, but nothing I've hit
upon has been productive so far. Any tips would be helpful; for example, how would I go about doing something like ls | grep lisp from the shell?

One of my attempts is

(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))))) 

Running this in a SLIME REPL causes everything to hang until I break
with C-c C-c, so it's pretty obviously not the right thing, but I'm
not sure how to change it so it is the right thing.

EDIT: Adding :WAIT NIL to both RUN-PROGRAM invocations, or to only the invocation for grep, doesn't do the trick. In that case, the function will hang, and breaking with C-c C-c gets a stack trace indicating that there's a local function (defined via FLET) called SB-UNIX:SELECT that has hung.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

献世佛 2024-08-30 19:56:19

我在 comp.lang.lisp。他的解决方案适用于 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))))) 

我还尝试了省略 lsRUN-PROGRAM 调用中的 :WAIT NIL 参数,效果也一样。

I got a working answer from Raymond Toy on comp.lang.lisp. His solution was for CMUCL, but it worked with the essentially identical RUN-PROGRAM function on the closely related SBCL, and with minor changes it will work on CCL as well, because CCL's RUN-PROGRAM is basically a clone of the one from CMUCL/SBCL.

The secret, as it were, is to set up the ls process first, and then provide its output stream to the grep process as input, like so:

(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))))) 

I also experimented with omitting the :WAIT NIL argument from the RUN-PROGRAM call for ls, and it worked just as well.

森末i 2024-08-30 19:56:19

使用 UIOP(包含在 ASDF 中,随实现一起提供)的跨实现的可移植解决方案:

(uiop:run-program "grep lisp"
                   :input
                   (uiop:process-info-output
                    (uiop:launch-program "ls"
                                         :output :stream))
                   :output :string)

launch-program 是同步的并输出到流,而 run-program 是异步的,我们要求它输出到一个字符串。

A portable solution across implementations, using UIOP (included in ASDF, shipped with the implementations):

(uiop:run-program "grep lisp"
                   :input
                   (uiop:process-info-output
                    (uiop:launch-program "ls"
                                         :output :stream))
                   :output :string)

launch-program is synchronous and outputs to a stream, while run-program is async, and we ask it to output to a string.

云巢 2024-08-30 19:56:19

尝试将 :wait nil 添加到 run-program 的参数中。那应该让你的 grep 和 ls 在后台运行。现在,您正在启动 grep 进程,等待其完成,然后启动要输入到 grep 进程中的 ls 。唉,由于您正在等待 grep 完成,所以您永远不会走那么远。

Try adding :wait nil to your arguments to run-program. That should have both your grep and your ls running in the background. As is, you're starting the grep process, waiting for that to finish, then starting the ls you're intending to feed into the grep process. Alas, since you're waiting for the grep to finish, you never get that far.

深空失忆 2024-08-30 19:56:19

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

(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)

Relatedly, but perhaps not spot on to your question, you could do:

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

or

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

or

(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)

And, of course, you can use

(format nil "ls ~a" directory)

To get input, you can do something like:

(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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文