From: Teemu Likonen on
I'm studying streams and CLISP's EXT:RUN-PROGRAM. As an exercise I wrote
a function which runs an external program and returns its output as a
list of strings. Each output line gets its own string in the list. The
function works but I want to make sure I'm doing it correctly. Here it
is:


(defun my-command (command &optional arguments)
(let ((stream (ext:run-program command :arguments arguments
:output :stream :wait t)))
(unwind-protect
(loop for line = (read-line stream nil)
while line
collect line)
(when (streamp stream)
(close stream)))))

A stupid example:

(my-command "/usr/bin/printf" '("Line %d\\n" "1" "2" "3"))
=> ("Line 1" "Line 2" "Line 3")


My questions: What happens if stream is not closed? Is UNWIND-PROTECT a
good way handle closing a stream?
From: vanekl on
On Mar 2, 1:23 pm, Teemu Likonen <tliko...(a)iki.fi> wrote:
> I'm studying streams and CLISP's EXT:RUN-PROGRAM. As an exercise I wrote
> a function which runs an external program and returns its output as a
> list of strings. Each output line gets its own string in the list. The
> function works but I want to make sure I'm doing it correctly. Here it
> is:
>
>     (defun my-command (command &optional arguments)
>       (let ((stream (ext:run-program command :arguments arguments
>                                      :output :stream :wait t)))
>         (unwind-protect
>              (loop for line = (read-line stream nil)
>                 while line
>                 collect line)
>           (when (streamp stream)
>             (close stream)))))
>
> A stupid example:
>
>     (my-command "/usr/bin/printf" '("Line %d\\n" "1" "2" "3"))
>     => ("Line 1" "Line 2" "Line 3")
>
> My questions: What happens if stream is not closed? Is UNWIND-PROTECT a
> good way handle closing a stream?

1. 'with-open-stream' should take care of closing the stream for you.

2. Something similar to this was discussed just two or three days ago
in this group. You may want to reference that thread ('RUN-PROGRAM' is
in title).

3. You could you 'ps' and 'lsof' to see for yourself what happens if
the stream is prematurely aborted (if anything).

On debian/sbcl:

# install admin programs
sudo apt-get install procps
sudo apt-get install lsof

# list open files
lsof -p `pgrep sbcl`

# list your printf process (if it's still open)
ps -ef | grep printf
From: Pascal J. Bourguignon on
Teemu Likonen <tlikonen(a)iki.fi> writes:

> I'm studying streams and CLISP's EXT:RUN-PROGRAM. As an exercise I wrote
> a function which runs an external program and returns its output as a
> list of strings. Each output line gets its own string in the list. The
> function works but I want to make sure I'm doing it correctly. Here it
> is:
>
>
> (defun my-command (command &optional arguments)
> (let ((stream (ext:run-program command :arguments arguments
> :output :stream :wait t)))
> (unwind-protect
> (loop for line = (read-line stream nil)
> while line
> collect line)
> (when (streamp stream)
> (close stream)))))
>
> A stupid example:
>
> (my-command "/usr/bin/printf" '("Line %d\\n" "1" "2" "3"))
> => ("Line 1" "Line 2" "Line 3")
>
>
> My questions: What happens if stream is not closed? Is UNWIND-PROTECT a
> good way handle closing a stream?

Subject to verification, ISTR that :wait t will make clisp wait for the
process to exit before returning from run-program. Therefore if the
process outputs more than a buffer worth, it will deadlock.

When you want to process the output of a process, you should fork it
without waiting on it.


So I would write it as:

(defun run-command (command &optional arguments)
(with-open-stream (pipe (ext:run-program command :arguments arguments
:output :stream :wait nil))
(loop
:for line = (read-line pipe nil nil)
:while line :collect line)))



However it looks like :wait is ignored when you specify :input or
:output streams.

--
__Pascal Bourguignon__
http://www.informatimago.com
From: Teemu Likonen on
* 2010-03-02 11:30 (-0800), vanekl wrote:

> 1. 'with-open-stream' should take care of closing the stream for you.

Ah, thanks. There seem to be many WITH-EVERYTHING-IMPLEMENTED-ALREADY
macros in Common Lisp.