【问题标题】:Executing a shell command from Common Lisp从 Common Lisp 执行 shell 命令
【发布时间】:2011-05-19 22:16:25
【问题描述】:

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

【问题讨论】:

    标签: bash shell lisp exec common-lisp


    【解决方案1】:

    ITA 在其 QITAB 伞形项目下发布了 inferior-shell

    一些可能感兴趣的链接:

    git 存储库目前托管在 common-lisp.net 上:

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

    【讨论】:

    • 除了 git repo,:inferior-shell 可以通过quicklisp 安装。
    • 为了更好的理解注意:inferior-shell使用uiop的函数run-program(同步的,launch-program是异步的)。
    【解决方案2】:

    ASDF 提供了一个RUN-SHELL-COMMAND,可与许多 Common Lisp 实现一起使用,包括 ABCL、Allegro CL、CLISP、Clozure CL、ECL、GCL、LispWorks、SBCL、CMU、XCL 和 SCL。

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

    【讨论】:

    • 请记住,从ASDF documentationrun-shell-command:“此功能已过时,仅为了向后兼容而存在:“如果不向后兼容,则不兼容”。我们强烈反对使用它。它的当前行为仅在 Unix 平台(包括 MacOS X 和 cygwin)上定义良好。在 Windows 上,一切正常。以下文档仅用于您以保留的方式迁移离开它语义。”
    • 如果它已被弃用,还有什么替代方案?
    • 根据文档,run-program 优于 run-shell-command
    • 您可以找到run-program 文档here 和简单的使用示例here
    • @ftravers 只要您只打算在 POSIX 系统上编程,那么run-shell-command 就没有问题。 它只是被认为是不推荐使用的,因为 它在 Windows 上不起作用
    【解决方案3】:

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

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

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

    asdf.lisp 文件中你可以阅读:

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

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

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

    ;;;;它,即使它已被弃用,我们也会支持它一段时间

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

    【讨论】:

    • 根据trivial-shell page on Cliki:“注意:现在你可能更喜欢inferior-shell,因为它有更广泛的支持和更丰富的界面。”
    【解决方案4】:

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

    UIOP readme

    【讨论】:

    • 您的链接已损坏
    • 已修复,感谢您的注意。顺便说一句,那是我的第一篇 stackoverflow 帖子,我想先发表评论,但不能,因为我需要 50 karma 之类的东西(现在它似乎可以工作了)。
    【解决方案5】:

    在 sbcl 中:

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

    它对我来说很好:)

    【讨论】:

      【解决方案6】:

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

      【讨论】:

        【解决方案7】:

        这个 (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 "") 仍然适用,即使它已经成为“遗留”功能。

        【讨论】:

          【解决方案8】:

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

          (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 程序员的书架......

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-06-15
            • 1970-01-01
            • 2013-12-16
            • 2014-04-21
            • 2014-01-22
            相关资源
            最近更新 更多