DEV Community

Vee Satayamas
Vee Satayamas

Posted on

Piping between Common Lisp and external command line

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*)
Enter fullscreen mode Exit fullscreen mode

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))
Enter fullscreen mode Exit fullscreen mode

(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"))
Enter fullscreen mode Exit fullscreen mode

(3) I get an output stream for passing data to the external program.

(setf *out* (external-program:process-input-stream *x*))
Enter fullscreen mode Exit fullscreen mode

(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*))
Enter fullscreen mode Exit fullscreen mode

At this step, you should see some output from the (2) step, which are:

OUT: !!! 1
OUT: !!! 2
...
OUT: !!! 10
Enter fullscreen mode Exit fullscreen mode

You can keep playing with it.

(5) And finally I clean everything up.

(close *out*)
(bordeaux-threads:join-thread *read-thread*)
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
kwccoin profile image
Kowloon walled city (coin) • Edited

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.