【问题标题】:Portable command execution syntax implemented in Python用 Python 实现的可移植命令执行语法
【发布时间】:2010-11-17 23:05:49
【问题描述】:

Python 在定义一组要运行的命令方面并不是一门很好的语言。巴什是。但是 Bash 不能在 Windows 上天真地运行。

背景:我正在尝试在 mac/win/linux 上构建一组程序——它们之间建立了依赖关系。类似于 macports 的东西,但应该适用于列出的所有三个平台。

这就需要有一种类似于 shell 的语言,该语言可用于定义为构建/修补/等运行的命令序列。一个特定的程序,例如:

post-destroot {
    xinstall -d ${destroot}${prefix}/share/emacs/${version}/leim
    delete ${destroot}${prefix}/bin/ctags
    delete ${destroot}${prefix}/share/man/man1/ctags.1
    if {[variant_isset carbon]} {
        global version
        delete ${destroot}${prefix}/bin/emacs ${destroot}${prefix}/bin/emacs-${version}
    }
}

以上来自emacs Portfile in macports。注意变量、条件、函数的使用......除了指定一个简单的命令列表以按该顺序执行。

虽然语法不是 Python,但实际的执行语义必须使用 subprocess 或其他方式推迟到 Python。简而言之,我应该能够“运行”这样的脚本......但是对于每个命令,都会调用一个指定的钩子函数,该函数实际上运行作为参数传递的任何命令。我希望你能明白。

【问题讨论】:

  • 你在这里要求什么?设计建议?一个代码sn-p?请更准确。
  • 我不是要代码 sn-p;但是关于如何实现或重用这样的命令解释器的想法(似乎 macports 使用 Tcl)

标签: python shell cross-platform command


【解决方案1】:

这是我的小建议:通过正则表达式将其解析为 Python,使其变为

def post_destroot():
    xinstall ('-d', '${destroot}${prefix}/share/emacs/${version}/leim')
    delete ('${destroot}${prefix}/bin/ctags')
    delete ('${destroot}${prefix}/share/man/man1/ctags.1')
    if test('variant_isset', 'carbon'):
        global('version')
        delete('${destroot}${prefix}/bin/emacs', '${destroot}${prefix}/bin/emacs-${version}')

我认为编写xinstall()delete()test() 函数并不难,尤其是因为Python 已经内置了格式化字符串的函数"{destroot}".format(dictionary).

但是为什么要麻烦呢?尝试从标准库中查看 distutils 模块。

【讨论】:

    【解决方案2】:

    Ned Batchelder 在this post 中列出了几十种不同的工具,您可能会选择在 Python 中对某些任意语言进行解析(尽管我不太明白为什么您不想将 Python 本身用作您的“定义一组要运行的命令的语言”,我相信您有自己的理由)。正如 Gregg 所提到的,Ned 列出的其中一个工具是 pyparsing,但还有 30 多个其他工具,因此您可能需要先查看一下,然后再选择适合自己的工具。

    一旦您将输入源语言转换为语法树或其他方便的内存表示,您就可以遍历树并随时执行(插入变量值、条件分支和循环等)。除了运行外部进程的能力(例如,通过子进程,无论是否按照 Gregg 的建议进行包装),不要忘记 Python 本身可能能够毫不费力地执行一些基本命令,并且在可行的情况下,这将比将执行委派给子进程快得多(实际上,Perl 成功的一个早期动机是它可以在一个进程中做很多事情,而 sh 正在疯狂地分叉;sh 的现代后代喜欢 bash 和 ksh吸取了教训,现在实现了许多可以在与主脚本相同的进程中执行的内置函数;-)。

    例如,您示例中的 delete 命令可以通过 os.unlink “内部”实现(目前无法链接到 Python 在线文档,因为由于硬件问题,python.org 目前已关闭;-) .

    【讨论】:

      【解决方案3】:

      听起来您需要PyParsingPython Subprocess 的某种组合。

      我发现 subprocess 有点令人困惑,尽管 MOTW 关于它,所以我经常使用这种包装代码。

      from subprocess import Popen, PIPE
      
      def shell(args, input=None):
          p = Popen(args, stdin=PIPE, stdout=PIPE, stderr=PIPE)
          stdout, stderr = p.communicate(input=input)
          return stdout, stderr
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多