Does there exist standard way to run external program in Common Lisp?
Asked Answered
S

6

13

In clisp, the following code works:

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

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

Selassie answered 11/10, 2011 at 3:24 Comment(0)
F
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>
Friedman answered 11/10, 2011 at 4:24 Comment(6)
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-*.)Profligate
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.)Friedman
trivial-shell is deprecated and replaced by inferior-shell, which simply uses uiop run-program (sync). For async, see uiop's launch-program.Wiley
@Wiley Well, if you think my answer deserves a downvote because of that, so be it. It still answers the actual question correctly, though.Friedman
@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).Wiley
@Wiley 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.Friedman
W
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.

Wiley answered 26/12, 2016 at 21:26 Comment(0)
O
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

Orlop answered 12/8, 2012 at 0:33 Comment(1)
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)))Miterwort
P
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*) 
Pathogen answered 9/4, 2014 at 22:0 Comment(1)
Please copy relevant snippets of code into the answer itself to prevent link-rot from turning the answer useless.Fallacy
D
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))
Dharna answered 28/4, 2015 at 23:11 Comment(0)
W
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.

Wiley answered 23/7, 2017 at 5:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.