bash 从 Common Lisp 执行 shell 命令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6065446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 00:01:51  来源:igfitidea点击:

Executing a shell command from Common Lisp

bashshelllispexeccommon-lisp

提问by Erhan Bagdemir

How can i execute a shell (bash) command within a Common Lisp program and assign the output to a variable?

如何在 Common Lisp 程序中执行 shell (bash) 命令并将输出分配给变量?

采纳答案by Terje Norderhaug

ASDFprovides a RUN-SHELL-COMMANDthat works with many Common Lisp implementationsincluding ABCL, Allegro CL, CLISP, Clozure CL, ECL, GCL, LispWorks, SBCL, CMU, XCL and SCL.

ASDF提供了一个RUN-SHELL-COMMAND适用于许多 Common Lisp 实现的工具,包括 ABCL、Allegro CL、CLISP、Clozure CL、ECL、GCL、LispWorks、SBCL、CMU、XCL 和 SCL。

It takes a control string and a list of arguments like FORMAT, and synchronously executes the result using a Bourne-compatible shell. Capture output by binding an optional stream.

它接受一个控制字符串和一个参数列表,如FORMAT,并使用与 Bourne 兼容的 shell 同步执行结果。通过绑定可选流来捕获输出。

回答by thodg

ITA has released inferior-shellunder their QITAB umbrella project.

ITA 已在其 QITAB 伞形项目下发布了低级 shell

Some links of possible interest :

一些可能感兴趣的链接:

A git repository is currently hosted at common-lisp.net :

一个 git 存储库当前托管在 common-lisp.net :

git clone git://common-lisp.net/projects/qitab/inferior-shell.git

回答by Spec

You can consider using Trivial-shell(url)

您可以考虑使用Trivial-shell( url)

(trivial-shell:shell-command "echo foo")

shell-command returns output, so you can assign it to a variable.

shell-command 返回输出,因此您可以将其分配给变量。

In asdf.lispfile you can read:

asdf.lisp文件中,您可以阅读:

;;;; We probably should move this functionality to its own system and deprecate

;;;; use of it from the asdf package. However, this would break unspecified

;;;; existing software, so until a clear alternative exists, we can't deprecate

;;;; it, and even after it's been deprecated, we will support it for a few

;;;; years so everyone has time to migrate away from it. -- fare 2009-12-01

;;;; 我们可能应该将此功能移至其自己的系统并弃用

;;;; 从 asdf 包中使用它。但是,这会破坏未指定的

;;;; 现有的软件,所以在存在明确的替代方案之前,我们不能弃用

;;;; 它,即使在它被弃用之后,我们也会支持它一些

;;;; 年,所以每个人都有时间远离它。-- 票价 2009-12-01

回答by Michael E.

Nowadays I would use uiop:run-program, where uiopstands for "universal input output" and is a compatibility layer provided by asdf3, formerly known as asdf/driver. As has been said asdf:run-shell-commandis obsolete and uiop inherits many features of other libraries such as trivial-shell.

现在我会使用uiop:run-program,其中uiop代表“通用输入输出”,是由 asdf3 提供的兼容层,以前称为asdf/driver. 如前所述已asdf:run-shell-command过时,uiop 继承了其他库的许多功能,例如trivial-shell.

UIOP readme

UIOP 自述文件

回答by Mars

Some CL implementations have built-in functions for this purpose. For example, SBCL has sb-ext:run-program, and CCL has run-program.

一些 CL 实现具有为此目的的内置函数。例如,SBCL 有sb-ext:run-program,CCL 有run-program

回答by lisperl

In sbcl:

在 sbcl 中:

(sb-ext:run-program "/bin/sh" (list "-c" "whoami") :input nil :output *standard-output*)

It works fine for me:)

这对我来说可以:)

回答by oOpSgEo

This (appupdate.cl) program is an example of creating and executing a shell script using the Steel Bank Common Lisp (sbcl) implementation, which assumes you have sbcl installed and its in your path.

这个 (appupdate.cl) 程序是使用 Steel Bank Common Lisp (sbcl) 实现创建和执行 shell 脚本的示例,它假定您已经安装了 sbcl 并且它在您的路径中。

I wrote this on Ubuntu 14.04 as a simple way to perform the automation of the updating, upgrading, and kernel upgrading of the app/system software.

我在 Ubuntu 14.04 上写了这个,作为一种简单的方法来执行应用程序/系统软件的更新、升级和内核升级的自动化。

#!/usr/local/bin/sbcl --script
(with-open-file (str "/home/geo/update.sh"
                     :direction :output
                     :if-exists :supersede
                     :if-does-not-exist :create)
  (format str "#! /bin/bash~%~%apt-get update~%~%apt-get upgrade -y~%~%apt-get dist-upgrade -y~%~%exit~%))
(sb-ext:run-program "/bin/chmod" '("+x" "/home/geo/update.sh")
    :output *standard-output*)
(sb-ext:run-program "/bin/bash" '("/home/geo/update.sh")
    :output *standard-output*)
(sb-ext:run-program "/bin/rm" '("-rf" "/home/geo/update.sh")
    :output *standard-output*)

So of course it creates a shell script entitled update.sh, which is directed to /bin/bash via shebang (#!). After doing so the sb-ext:run-program built directs a shell to execute /bin/chmod passing the flag "+x" as an argument and the /path/to/the-file. This function changes the mode of access of the file to executable (changes the permissions).

所以当然它会创建一个名为 update.sh 的 shell 脚本,它通过 shebang (#!) 定向到 /bin/bash。执行此操作后,构建的 sb-ext:run-program 指示 shell 执行 /bin/chmod,将标志“+x”作为参数和 /path/to/the-file 传递。此函数将文件的访问模式更改为可执行文件(更改权限)。

Next, a shell is open and executes /bin/bash and the bash binary is passed the argument of the executable shell scripts file location.

接下来,打开一个 shell 并执行 /bin/bash 并且向 bash 二进制文件传递可执行 shell 脚本文件位置的参数。

Lastly the file is removed from the working directory (note in this case the appupdate.cl is in my home directory therefore is the working directory).

最后,文件从工作目录中删除(注意在这种情况下 appupdate.cl 在我的主目录中,因此是工作目录)。

The appupdate.cl file can be executed from the command line after it is changed to executable and temporary root privileges are gained:

将appupdate.cl文件改为可执行文件并获得临时root权限后,就可以从命令行执行了:

:~$ chmod +x appupdate.cl

:~$ sudo bash

:~# ./appupdate.cl

:~# exit

Easily enough the sudo command could be added to the script (e.g. sudo apt-get update) and using the sudo bash sequence would not be necessary.

sudo 命令可以很容易地添加到脚本中(例如 sudo apt-get update)并且不需要使用 sudo bash 序列。

NOTE: In the LispWorks ide on 14.04 the (sys:run-shell-command "") is still applicable even though it has sort of become a 'legacy' function.

注意:在 14.04 的 LispWorks ide 中,(sys:run-shell-command "") 仍然适用,即使它已经成为一个“遗留”功能。

回答by Gwang-Jin Kim

I tried out some answers but it was not straightforward. This is what worked easily:

我尝试了一些答案,但这并不简单。这很容易奏效:

(ql:quickload "external-program")
;; run shell command e.g. "ls -l" and capture the output into string *output*
(defparameter *output* 
              (with-output-to-string (out) 
                (external-program:run "ls" '("-l")  ; command with parameters as list of strings
                                      :output out)))
;; and after that, you can write functions to parse the output ...

This is from Edi Weitz's book Common Lisp Recipeswhich belongs to the shelve of any serious Lisp programmer, in my view...

这是 Edi Weitz 的书Common Lisp Recipes,在我看来,它属于任何认真的 Lisp 程序员的书架……