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.