无法让输入流在 SBCL sb-ext:运行-program 中工作
Cannot get input stream working in SBCL sb-ext:run-program
虽然以下有效:
(let* ((i (make-string-input-stream "foo bar baz"))
(p (sb-ext:run-program "/bin/cat" '()
:input i :output *trace-output* :wait t)))
(sb-ext:process-close p))
下面的代码不会 - 它会在写入“001”后停止:
(let* ((_1 (format t "001~%"))
(p (sb-ext:run-program "/bin/cat" '()
:input :stream :output *trace-output* :wait t))
(_2 (format t "010~s~%" p))
(s (sb-ext:process-input p)))
(declare (ignore _1 _2))
(format s "foo bar baz~%")
(finish-output s)
(sb-ext:process-close p))
所以它似乎在 sb-ext:run-program
中默默地离开了执行。
这是 Ubuntu 16.04.1 上的 SBCL 1.3.6。
有什么想法吗?提前致谢,弗兰克
正如我在评论中提到的,问题出在 :WAIT T
参数上。它会导致对 SB-EXT:RUN-PROGRAM
的调用不会 return 直到子进程退出。
在第一个示例中,您将字符串输入流传递给了子进程。 cat
将从流中读取输入,当输入结束时将出现文件结尾,因此 cat
退出。在第二个例子中,程序没有可用的输入,所以它实际上是一个无限循环(就像如果你在命令行上 运行 cat
,并且不给它任何输入;它永远不会退出)。
解决方案是使用:WAIT NIL
。您还必须使用 CLOSE
关闭输入流,否则将没有 EOF 并且 cat
会继续监听更多输入。您还需要在关闭流后使用 SB-EXT:PROCESS-WAIT
等待 cat
自行退出。
(let* ((p (sb-ext:run-program "/bin/cat" '()
:input :stream
:output *standard-output*
:wait nil))
(s (sb-ext:process-input p)))
(format s "foo bar baz~%")
(finish-output s)
(close s)
(sb-ext:process-wait p)
(sb-ext:process-close p))
我不确定你为什么使用 *TRACE-OUTPUT*
作为子输出,所以我将其更改为 *STANDARD-OUTPUT*
。
此外,使用 FORMAT
进行这样的调试有点丑陋。 Common Lisp 提供了实际的调试工具。在这种情况下,您可以使用 STEP
:
(step (let* ((p (sb-ext:run-program "/bin/cat" '()
:input :stream
:output *standard-output*
:wait nil))
(s (sb-ext:process-input p)))
(format s "foo bar baz~%")
(finish-output s)
(close s)
(sb-ext:process-wait p)
(sb-ext:process-close p)))
这将使您进入调试器,显示接下来正在评估的调用。您可以调用 STEP-NEXT
-restart 以继续下一个调用。
这是有效的方法,正如 jkiiski 所建议的那样:
(let* ((p (sb-ext:run-program "/bin/cat" '()
:input :stream
:output *standard-output*
:wait nil))
(s (sb-ext:process-input p)))
(format s "foo bar baz~%")
(finish-output s)
(sb-ext:process-wait p)
(sb-ext:process-close p))
虽然以下有效:
(let* ((i (make-string-input-stream "foo bar baz"))
(p (sb-ext:run-program "/bin/cat" '()
:input i :output *trace-output* :wait t)))
(sb-ext:process-close p))
下面的代码不会 - 它会在写入“001”后停止:
(let* ((_1 (format t "001~%"))
(p (sb-ext:run-program "/bin/cat" '()
:input :stream :output *trace-output* :wait t))
(_2 (format t "010~s~%" p))
(s (sb-ext:process-input p)))
(declare (ignore _1 _2))
(format s "foo bar baz~%")
(finish-output s)
(sb-ext:process-close p))
所以它似乎在 sb-ext:run-program
中默默地离开了执行。
这是 Ubuntu 16.04.1 上的 SBCL 1.3.6。
有什么想法吗?提前致谢,弗兰克
正如我在评论中提到的,问题出在 :WAIT T
参数上。它会导致对 SB-EXT:RUN-PROGRAM
的调用不会 return 直到子进程退出。
在第一个示例中,您将字符串输入流传递给了子进程。 cat
将从流中读取输入,当输入结束时将出现文件结尾,因此 cat
退出。在第二个例子中,程序没有可用的输入,所以它实际上是一个无限循环(就像如果你在命令行上 运行 cat
,并且不给它任何输入;它永远不会退出)。
解决方案是使用:WAIT NIL
。您还必须使用 CLOSE
关闭输入流,否则将没有 EOF 并且 cat
会继续监听更多输入。您还需要在关闭流后使用 SB-EXT:PROCESS-WAIT
等待 cat
自行退出。
(let* ((p (sb-ext:run-program "/bin/cat" '()
:input :stream
:output *standard-output*
:wait nil))
(s (sb-ext:process-input p)))
(format s "foo bar baz~%")
(finish-output s)
(close s)
(sb-ext:process-wait p)
(sb-ext:process-close p))
我不确定你为什么使用 *TRACE-OUTPUT*
作为子输出,所以我将其更改为 *STANDARD-OUTPUT*
。
此外,使用 FORMAT
进行这样的调试有点丑陋。 Common Lisp 提供了实际的调试工具。在这种情况下,您可以使用 STEP
:
(step (let* ((p (sb-ext:run-program "/bin/cat" '()
:input :stream
:output *standard-output*
:wait nil))
(s (sb-ext:process-input p)))
(format s "foo bar baz~%")
(finish-output s)
(close s)
(sb-ext:process-wait p)
(sb-ext:process-close p)))
这将使您进入调试器,显示接下来正在评估的调用。您可以调用 STEP-NEXT
-restart 以继续下一个调用。
这是有效的方法,正如 jkiiski 所建议的那样:
(let* ((p (sb-ext:run-program "/bin/cat" '()
:input :stream
:output *standard-output*
:wait nil))
(s (sb-ext:process-input p)))
(format s "foo bar baz~%")
(finish-output s)
(sb-ext:process-wait p)
(sb-ext:process-close p))