Reputation: 105
While the following works:
(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))
the code below does not - it will stop after writing "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))
So it seems to silently leave execution in sb-ext:run-program
.
This is with SBCL 1.3.6 on Ubuntu 16.04.1.
Any ideas? Thanks in advance, Frank
Upvotes: 1
Views: 452
Reputation: 105
This is what works, as suggested by 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))
Upvotes: 0
Reputation: 8411
As I mentioned in the comments, the problem is the :WAIT T
argument. It causes the call to SB-EXT:RUN-PROGRAM
to not return until the child process exits.
In the first example you passed a string input stream to the child process. cat
will read input from the stream, and when the input ends there will be a End of File, so cat
exits. In the second example there is no input available for the program, so it's effectively an infinite loop (just like if you run cat
on the command line, and don't give any input to it; it will never exit).
The solution is to use :WAIT NIL
. You will also have to close the input stream with CLOSE
, because otherwise there will be no EOF and cat
keeps listening for more input. You'll also want to use SB-EXT:PROCESS-WAIT
after closing the stream to wait for cat
to exit itself.
(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))
I'm not sure why you used *TRACE-OUTPUT*
for the child output, so I changed it to *STANDARD-OUTPUT*
.
Also, using FORMAT
for debugging like that is kind of ugly. Common Lisp provides actual debugging tools. In this case you could use 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)))
This will put you in the debugger, showing the call being evaluated next. You can invoke the STEP-NEXT
-restart to continue to the next call.
Upvotes: 3