13

In clisp, the following code works:

(defun hit-history () (shell "tail ssqHitNum.txt"))

However, in Clozure CL, the shell function is not supported!

Mateusz Piotrowski
  • 8,029
  • 10
  • 53
  • 79
z_axis
  • 8,272
  • 7
  • 41
  • 61

6 Answers6

12

No, there is no standard way, but there are libraries which provide this functionality for the important implementations. For example, there's trivial-shell available in Quicklisp, which provides shell-command. (I didn't actually test it, but its among the recommended libraries on CLiki.) There is also external-program. Update: inferior-shell seems to be prefered these days, as Ehvince points out in a comment and his own answer.

You could also use read-time conditionals to make different implementations use their respective functionality to do this.

CCL has ccl:run-program, for example:

CL-USER> (run-program "whoami" '() :output *standard-output*)
foobar
#<EXTERNAL-PROCESS (whoami)[NIL] (EXITED : 0) #xC695EA6>
danlei
  • 14,121
  • 5
  • 58
  • 82
  • Note that you don't need Quicklisp to use the excellent `trivial-shell` library. Also, I'm not sure the reasoning behind the "read-time conditionals" suggestion, since that is exactly what trivial-shell does. (That's why such libraries are called trivial-*.) – Ken Oct 17 '11 at 18:35
  • 3
    Ken, yes, one doesn't *need* to use Quicklisp, but it's what is usually recommended for installing Lisp libraries these days. Feel free to add your own answer explaining how to install by hand. I mentioned read-time-conditionals, because the OP might not want to use a library for some reason, and it's also good to know about it, if for example no trivial-* exists for similar problems. (And, of course, there are also other uses for read-time conditionals, so its good to know about them anyway.) – danlei Oct 17 '11 at 20:21
  • `trivial-shell` is deprecated and replaced by [inferior-shell](https://gitlab.common-lisp.net/qitab/inferior-shell), which simply uses [uiop](http://cliki.net/uiop) `run-program` (sync). For async, see uiop's `launch-program`. – Ehvince Dec 26 '16 at 21:23
  • @Ehvince Well, if you think my answer deserves a downvote because of that, so be it. It still answers the actual question correctly, though. – danlei Jan 03 '17 at 18:50
  • @daniel I wish newer answers had more votes but maybe a downvote isn't the solution, sorry. I canceled it (even more since you edited your question). – Ehvince Jan 03 '17 at 23:39
  • @Ehvince I see. Personally, I only downvote an answer when it's really wrong or of very bad quality. When I prefer another answer to the accepted one, I usually just upvote it and leave the accepted one alone. But I agree that there is a problem with language or ecosystem changes, when you have an outdated answer on top and the better answers lack visibility. Anyway, I'm glad you left a comment to let me know what was going on. What I really hate are downvotes where I have no clue what someone thought was wrong with my answer. Also thanks for reverting the downvote. – danlei Jan 04 '17 at 00:38
8

Yes, with UIOP, part of ASDF, that should be included in all modern implementations.

  • synchronous commands: uiop:run-program
  • asynchronous commands: uiop:launch-program

So for example

(uiop:run-program (list "firefox" "http:url") :output t)

or

(defparameter *shell* (uiop:launch-program "bash" :input :stream :output :stream))

where you can send input and read output.

They are more explained here: https://lispcookbook.github.io/cl-cookbook/os.html#running-external-programs

trivial-shell is deprecated and replaced by inferior-shell, which internally uses the portable uiop's run-program (synchronous), so we can use just that.

Ehvince
  • 17,274
  • 7
  • 58
  • 79
2
(defun dot->png (fname thunk)
   (with-open-file (*standard-output*
       fname
       :direction :output
       :if-exists :superseded)
     (funcall thunk))
   (ccl:run-program "dot" (list "-Tpng -O" fname))
)

i run success in ccl(clozure),when study land of lisp p123

  • This was helpful to me when reading the same passage for Land of Lisp. I was using SBCL and had to change the last line to `(sb-ext:run-program "/usr/bin/dot" (list "-Tpng" "-O" fname)))` – dpritch Apr 01 '18 at 16:31
1

The following shows an example of calling wget from within common lisp:

https://diasp.eu/posts/1742240

Here's the code:

(sb-ext:run-program "/usr/bin/wget" '("-O" "<path-to-output-file>" "<url-link>") :output *standard-output*) 
  • Please copy relevant snippets of code into the answer itself to prevent link-rot from turning the answer useless. – EWit Apr 09 '14 at 22:19
1

Have a look at the inferior-shell package.

(Get it via the almighty quicklisp package manager.)

This works in the interpreter, if you have internet:

(require 'inferior-shell)
(inferior-shell:run/s '(curl icanhazip.com))
sjas
  • 18,644
  • 14
  • 87
  • 92
0

CL21 defines simple methods:

(in-package :cl21-user)
(use-package :cl21.process)

Then either with run-process or with the #` reader macro:

(run-process '("ls" "-l"))
;-> total 0
;   drwxrwxrwt    5 root         wheel   170 Nov  1 18:00 Shared
;   drwxr-xr-x+ 174 nitro_idiot  staff  5916 Mar  5 21:41 nitro_idiot
;=> #<PROCESS /bin/sh -c ls -l /Users (76468) EXITED 0>

or

#`ls -l /Users`
;=> "total 0
;   drwxrwxrwt    5 root         wheel   170 Nov  1 18:00 Shared
;   drwxr-xr-x+ 174 nitro_idiot  staff  5916 Mar  5 21:41 nitro_idiot
;   "
;   ""
;   0

The source shows implementation for SBCL and CCL.

Ehvince
  • 17,274
  • 7
  • 58
  • 79