4

I'm trying to create a "system" command for clisp that works like this

(setq result (system "pwd"))

;;now result is equal to /my/path/here

I have something like this:

(defun system (cmd)
 (ext:run-program :output :stream))

But, I am not sure how to transform a stream into a string. I've reviewed the hyperspec and google more than a few times.

edit: working with Ranier's command and using with-output-to-stream,

(defun system (cmd)
  (with-output-to-string (stream)
    (ext:run-program cmd :output stream)))

And then trying to run grep, which is in my path...

[11]> (system "grep")

*** - STRING: argument #<OUTPUT STRING-OUTPUT-STREAM> should be a string, a
      symbol or a character
The following restarts are available:
USE-VALUE      :R1      Input a value to be used instead.
ABORT          :R2      Abort main loop
Break 1 [12]> :r2

4 Answers 4

5

Something like this?

Version 2:

(defun copy-stream (in out)
   (loop for line = (read-line in nil nil)
         while line
         do (write-line line out)))

(defun system (cmd)
  (with-open-stream (s1 (ext:run-program cmd :output :stream))
    (with-output-to-string (out)
      (copy-stream s1 out))))


[6]> (system "ls")
"#.emacs#
Applications
..."
Sign up to request clarification or add additional context in comments.

2 Comments

question: what does the :output indicate? is that a named parameter syntax?
:output is a parameter that sets where the output will be directed to. in this it'll be directed to a stream.
3

Per the CLISP documentation on run-program, the :output argument should be one of

  • :terminal - writes to the terminal
  • :stream - creates and returns an input stream from which you can read
  • a pathname designator - writes to the designated file
  • nil - ignores the output

If you're looking to collect the output into a string, you'll have to use a read-write copying loop to transfer the data from the returned stream to a string. You already have with-output-to-string in play, per Rainer's suggestion, but instead of providing that output stream to run-program, you'll need to write to it yourself, copying the data from the input stream returned by run-program.

Comments

2

You are asking specifically about clisp. I'll add here that if you are using Clozure CL then you can also easily run os subprocesses.

Some examples:

;;; Capture the output of the "uname" program in a lisp string-stream
;;; and return the generated string (which will contain a trailing
;;; newline.)
? (with-output-to-string (stream)
    (run-program "uname" '("-r") :output stream))
;;; Write a string to *STANDARD-OUTPUT*, the hard way.
? (run-program "cat" () :input (make-string-input-stream "hello") :output t)
;;; Find out that "ls" doesn't expand wildcards.
? (run-program "ls" '("*.lisp") :output t)
;;; Let the shell expand wildcards.
? (run-program "sh" '("-c" "ls *.lisp") :output t)

Do a search for run-program in the CCL docs located here: http://ccl.clozure.com/ccl-documentation.html

There are a couple nice Lisp ways of doing this in this stackoverflow answer: Making a system call that returns the stdout output as a string Once again, Rainer to the rescue. Thanks Ranier.

Comments

0

This is a shorter one

(defun system(cmd)
  (ext:shell (string cmd)))

> (system '"cd ..; ls -lrt; pwd")

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.