捕获cl-async:spawn的输出

时间:2018-03-19 21:59:30

标签: common-lisp

我希望尝试使用cl-async来运行一系列具有大量命令行参数的外部程序。但是,我无法弄清楚如何阅读使用as:spawn启动的流程的标准输出。

我通常会使用uiop,这样可以轻松捕获过程输出:

(let ((p (uiop:launch-program ... :output :stream)))
  (do-something-else-until-p-is-done)
  (format t "~a~%" (read-line (uiop:process-info-output p))))

我已经尝试了:output :pipe:output :stream两个as:spawn选项,并且在我的退出回调中执行(as:process-output process-object)会显示相应的管道或异步流对象但是我无法弄清楚如何阅读它们。

任何有此库经验的人都可以告诉我们如何实现这一目标吗?

2 个答案:

答案 0 :(得分:1)

所以你去你的repl并输入:

CL-USER> (documentation 'as:spawn 'function)

你阅读出来的任何内容(或者把你的观点放在符号上并点击C-c C-d f)。如果您阅读它,您会看到:input等参数的格式为:pipe(:pipe args...):stream(:stream args...)(或某些其他选择)。并且:stream的行为类似于:pipe,但提供了不同类型的输出,并且对于args的详细信息,应该查看PIPE-CONNECT,因此您可以查看文档。那么它告诉你选项是什么,但它不是很有用。什么是PIPESTREAM的文档/说明?事实证明,管道是STREAMISH的类和子类。那个PROCESS也是一个类,它有PROCESS-OUTPUT之类的插槽(和访问器)。那么如何确定下一步该做什么的好计划呢?这是一个建议:

  1. 使用cat foo.txt -
  2. 生成一个长时间运行的过程(如:output :stream :input :pipe
  3. 检查结果(C-c C-v TAB
  4. 希望它是PROCESS的一个实例。什么是输出?检查
  5. 希望输出是灰色流(ASYNC-STREAM)。把它放到你的repl中,看看如果你试着读它会发生什么?
  6. 输入怎么样?查看具有哪种类型以及可以使用它做什么
  7. 以上都是猜测。我没有试过运行任何这个,但你应该。或者,查看库的源代码。它已经在你的计算机上了,如果你找不到它就在GitHub上。只有大约六个源文件,它们都很小。只需阅读它们,看看你能学到什么。或者转到您想要了解的符号,然后点击M-.直接跳到其定义。然后阅读代码。然后看看你是否能弄明白该做什么。

答案 1 :(得分:1)

我在测试套件中找到了答案。输出流只能通过读回调异步处理。以下是后人的简单示例

(as:start-event-loop
  (lambda ()
    (let ((bytes (make-array 0 :element-type '(unsigned-byte 8))))
        (as:spawn "./test.sh" '()
                  :exit-cb (lambda (proc exit-status term-signal)
                              (declare (ignore proc exit-status term-signal))
                              (format t "proc output:~%~a"
                                (babel:octets-to-string bytes)))
                  :output (list :stream
                                :read-cb (lambda (pipe stream)
                                           (declare (ignore pipe))
                                           (let ((buf (make-array 128 :element-type '(unsigned-byte 8))))
                                             (loop for n = (read-sequence buf stream)
                                                while (plusp n) do
                                                   (setf bytes 
                                                        (concatenate  '(vector (unsigned-byte 8))
                                                          bytes
                                                         (subseq buf 0 n)))))))))))

$ cat test.sh
#!/bin/bash

sleep_time=$((1+$RANDOM%10))
echo "Process $$ will sleep for $sleep_time"
sleep $sleep_time
echo "Process $$ exiting"

产生预期的输出