With the external-program package, I can code to call an external command line program easily. For example:
(external-program:run "ls" '("-l") :output *standard-output*)
What if I want to keep streaming (piping) input and reading output. (1) instead of run, I use start.
(setf *x* (external-program:start "cat" '() :output :stream :input :stream))
(2) I create a thread for reading the output and print it. Bordeaux-threads API looks quite similar to POSIX.
(setf *read-thread*
(bordeaux-threads:make-thread
(lambda ()
(loop for line = (read-line (external-program:process-output-stream *x*) nil)
while line
do (format t "OUT: ~A~%" line)))
:name "titi"))
(3) I get an output stream for passing data to the external program.
(setf *out* (external-program:process-input-stream *x*))
(4) I write something to out and flash it.
(progn
(loop for i from 1 to 10
do (format *out* "!!! ~A~%" i))
(force-output *out*))
At this step, you should see some output from the (2) step, which are:
OUT: !!! 1
OUT: !!! 2
...
OUT: !!! 10
You can keep playing with it.
(5) And finally I clean everything up.
(close *out*)
(bordeaux-threads:join-thread *read-thread*)
Top comments (1)
Trying this and it is a good start.
Other than one need to quickload two packages and amend the setf to defparameter , I suspect there might be an issue as the bt-thread is another thread from the repl/swank thread (and macOS main display thread).
Run using sbcl --load "xxx.lisp" work ok, but only for cat and ls.
May need to dig deeper e.g. trying to do "ping 8.8.8.8 -I 5" and analysis the return out (for performance or future my own server alive stat with network turn around etc.) would not work. Try even "/sbin/ping ..." and create a sh file with chmod +x ... even though "ls" can find the file, the actual start does not. Guess need more work on my side.