【发布时间】:2011-05-19 22:16:25
【问题描述】:
如何在 Common Lisp 程序中执行 shell (bash) 命令并将输出分配给变量?
【问题讨论】:
标签: bash shell lisp exec common-lisp
如何在 Common Lisp 程序中执行 shell (bash) 命令并将输出分配给变量?
【问题讨论】:
标签: bash shell lisp exec common-lisp
ITA 在其 QITAB 伞形项目下发布了 inferior-shell。
一些可能感兴趣的链接:
git 存储库目前托管在 common-lisp.net 上:
git clone git://common-lisp.net/projects/qitab/inferior-shell.git
ASDF 提供了一个RUN-SHELL-COMMAND,可与许多 Common Lisp 实现一起使用,包括 ABCL、Allegro CL、CLISP、Clozure CL、ECL、GCL、LispWorks、SBCL、CMU、XCL 和 SCL。
它接受一个控制字符串和一个参数列表,如FORMAT,并使用与 Bourne 兼容的 shell 同步执行结果。通过绑定可选流来捕获输出。
【讨论】:
run-shell-command:“此功能已过时,仅为了向后兼容而存在:“如果不向后兼容,则不兼容”。我们强烈反对使用它。它的当前行为仅在 Unix 平台(包括 MacOS X 和 cygwin)上定义良好。在 Windows 上,一切正常。以下文档仅用于您以保留的方式迁移离开它语义。”
run-shell-command 就没有问题。 它只是被认为是不推荐使用的,因为 它在 Windows 上不起作用。
【讨论】:
现在我会使用uiop:run-program,其中uiop 代表“通用输入输出”,是asdf3 提供的兼容层,以前称为asdf/driver。如前所述,asdf:run-shell-command 已过时,uiop 继承了其他库的许多功能,例如trivial-shell。
【讨论】:
在 sbcl 中:
(sb-ext:run-program "/bin/sh" (list "-c" "whoami") :input nil :output *standard-output*)
它对我来说很好:)
【讨论】:
一些 CL 实现为此目的具有内置函数。例如,SBCL 有sb-ext:run-program,CCL 有run-program。
【讨论】:
这个 (appupdate.cl) 程序是使用 Steel Bank Common Lisp (sbcl) 实现创建和执行 shell 脚本的示例,它假定您已安装 sbcl 并且它在您的路径中。
我在 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*)
所以它当然会创建一个名为 update.sh 的 shell 脚本,该脚本通过 shebang (#!) 定向到 /bin/bash。这样做之后,构建的 sb-ext:run-program 会指示 shell 执行 /bin/chmod,并传递标志“+x”作为参数和 /path/to/the-file。此函数将文件的访问模式更改为可执行(更改权限)。
接下来,打开一个 shell 并执行 /bin/bash,并将 bash 二进制文件传递给可执行 shell 脚本文件位置的参数。
最后,文件从工作目录中删除(注意在这种情况下 appupdate.cl 在我的主目录中,因此是工作目录)。
appupdate.cl文件改成可执行文件并获得临时root权限后,即可在命令行执行:
:~$ chmod +x appupdate.cl
:~$ sudo bash
:~# ./appupdate.cl
:~# exit
sudo 命令可以很容易地添加到脚本中(例如 sudo apt-get update),并且不需要使用 sudo bash 序列。
注意:在 14.04 的 LispWorks ide 中,(sys:run-shell-command "") 仍然适用,即使它已经成为“遗留”功能。
【讨论】:
我尝试了一些答案,但并不简单。 这很容易奏效:
(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 ...
这是来自 Edi Weitz 的书 Common Lisp Recipes,在我看来,它属于任何认真的 Lisp 程序员的书架......
【讨论】: