【问题标题】:Embed bash in python在python中嵌入bash
【发布时间】:2011-02-08 18:16:05
【问题描述】:

我正在编写 Python 脚本,但时间不多了。我需要在 bash 中做一些我非常熟悉的事情,所以我只是想知道如何将一些 bash 行嵌入到 Python 脚本中。

谢谢

【问题讨论】:

  • -1:“一些事情”?如果您有特别需要帮助的事情,我们可以帮助您避免在 Python 中嵌入 bash 的错误。
  • @S.Lott 我知道这是很久以前的事了,但我只是第一次潜入 bash 脚本。我已经确定我肯定想尽可能使用 Python(这是我的主要语言 ATM)。有没有一种快速的方法来解释为什么在 Python 中嵌入 bash 是一个错误?

标签: python bash interop language-interoperability


【解决方案1】:

假设主机系统支持该命令:

import os
os.system('command')

如果您有一个长命令或一组命令。你可以使用变量。 例如:

# this simple line will capture column five of file.log
# and then removed blanklines, and gives output in filtered_content.txt.

import os

filter = "cat file.log | awk '{print $5}'| sed '/^$/d' > filtered_content.txt"

os.system(filter)

【讨论】:

    【解决方案2】:

    import os
    os.system ("bash -c 'echo $0'")
    

    会为你做吗?

    编辑:关于可读性

    是的,当然,你可以让它更具可读性

    import os
    script = """
    echo $0
    ls -l
    echo done
    """
    os.system("bash -c '%s'" % script)
    

    EDIT2:关于宏,据我所知,没有 python 没有做到这一点,但介于

    import os
    def sh(script):
        os.system("bash -c '%s'" % script)
    
    sh("echo $0")
    sh("ls -l")
    sh("echo done")
    

    和前面的例子一样,你基本上得到了你想要的(但你必须允许一些辩证的限制)

    【讨论】:

    • 太棒了!并且,是否有一些捷径或变通方法可以使它更容易或更吸引人?
    • 我的意思是,我可以在 python 中定义一些宏,比如;(#define sh os.system(" ....."),所以在我刚刚编写的代码中, sh ps -ef ?
    【解决方案3】:

    如果要调用系统命令,请使用subprocess 模块。

    【讨论】:

    • -1 用于使用 tinyurl 链接到 google 搜索,而不是指向直接有用的资源。
    • +1 最后的资源非常有用,并且是这个问题的正确答案。这是一个直接链接:docs.python.org/library/subprocess.html
    • @Donal,我这样做的原因是因为还有其他有用的站点也显示了子流程示例。此外,第一个搜索结果是文档本身。这根本不应该是问题。
    【解决方案4】:

    还有commands 模块可以更好地控制输出: https://docs.python.org/2/library/commands.html

    【讨论】:

    • @gander 我认为你被否决了,因为命令在 Python 中被弃用了。
    • 哦!不是一个好的开始。当然,它仍然对卡在旧版本上的人有效吗?
    【解决方案5】:

    理想的方法:

    def run_script(script, stdin=None):
        """Returns (stdout, stderr), raises error on non-zero return code"""
        import subprocess
        # Note: by using a list here (['bash', ...]) you avoid quoting issues, as the 
        # arguments are passed in exactly this order (spaces, quotes, and newlines won't
        # cause problems):
        proc = subprocess.Popen(['bash', '-c', script],
            stdout=subprocess.PIPE, stderr=subprocess.PIPE,
            stdin=subprocess.PIPE)
        stdout, stderr = proc.communicate()
        if proc.returncode:
            raise ScriptException(proc.returncode, stdout, stderr, script)
        return stdout, stderr
    
    class ScriptException(Exception):
        def __init__(self, returncode, stdout, stderr, script):
            self.returncode = returncode
            self.stdout = stdout
            self.stderr = stderr
            Exception().__init__('Error in script')
    

    您还可以向ScriptException 添加一个不错的__str__ 方法(您肯定需要它来调试您的脚本)——但我把它留给读者。

    如果您不使用stdout=subprocess.PIPE 等,脚本将直接附加到控制台。例如,如果您有来自 ssh 的密码提示,这将非常方便。因此,您可能需要添加标志来控制是否要捕获标准输出、标准错误和标准输入。

    【讨论】:

    • 我很确定这比他想要的要酷 10 倍。
    • 不错!添加到我的工具箱中。
    • 函数run_script的参数stdin有什么用?
    • 你为什么用-c
    • -c 告诉 bash 执行字符串。所以bash "echo hi" 会尝试执行名为“echo hi”的脚本file(这不起作用!),而bash -c "echo hi" 会尝试运行“echo hi”(并会显示“hi ")
    【解决方案6】:

    如前所述,您可以使用 os.system();它又快又脏,但它易于使用并且适用于大多数情况。它实际上是对 C system() 函数的映射。

    http://docs.python.org/2/library/os.html#os.system

    http://www.cplusplus.com/reference/cstdlib/system/

    【讨论】:

      【解决方案7】:
      当 bash 命令很简单并且没有括号、逗号和引号时,

      subprocess 和 os.system() 可以正常工作。 嵌入复杂 bash 参数的简单方法是在 python 脚本的末尾添加具有唯一字符串 cmets 的 bash 脚本,并使用简单的 os.system() 命令尾随并转换为 bash 文件。

      #!/usr/bin/python
      ## name this file  "file.py"
      import os
      def get_xred(xx,yy,zz):
          xred=[]
      ####gaur###
          xred.append([     zz[9] ,  zz[19] ,  zz[29]     ])
          xred.append([     zz[9] ,  xx[9]  ,  yy[9]      ])
          xred.append([     zz[10],  zz[20] ,  zz[30]     ])
          xred.append([     zz[10],  xx[10] ,  yy[10]     ])
      ###nitai###
          xred=np.array(xred)
          return xred
      ## following 3 lines executes last 6 lines of this file.
      os.system("tail -n 6 file.py >tmpfile1")
      os.system("sed 's/###123//g' tmpfile1>tmpfile2")
      os.system("bash tmpfile2")
      ###### Here ###123 is a unique string to be removed
      ###123#!/bin/sh
      ###123awk '/###gaur/{flag=1;next}/###nitai/{flag=0} flag{print}' file.py >tmp1
      ###123cat tmp1 | awk '{gsub("xred.append\\(\\[","");gsub("\\]\\)","");print}' >tmp2
      ###123awk 'NF >0' tmp2 > tmp3
      ###123sed '$d' tmp3 |sed '$d' | sed '$d' >rotation ; rm tmp*
      

      【讨论】:

        【解决方案8】:

        我创建 Sultan 正是为了解决您想要做的事情。它没有任何外部依赖项,并尝试尽可能轻量,并为 Bash 提供 Pythonic 接口。

        https://github.com/aeroxis/sultan

        【讨论】:

        • 苏丹看起来很酷,我要使用它;在该工具看起来真正有用/适用并且是开源的情况下,我认为人们不应该仅仅根据不喜欢任何看似自我推销的原则来投反对票。工具看起来不错!答案是合理的。
        【解决方案9】:

        @Ian Bicking 的回答很有用,但它只允许我们运行脚本。相反,我们可以提出一个更灵活的代码,我们也可以在其中运行命令。我和他的方法不同。

        #!/usr/bin/env python3
        
        from subprocess import Popen, PIPE
        
        
        class BashCommandsException(Exception):
            def __init__(self, returncode, output, error_msg):
                self.returncode = returncode
                self.output = output
                self.error_msg = error_msg
                Exception.__init__('Error in executed command')
        
        
        def popen_communicate(cmd, stdout_file=None):
            """Acts similir to lib.run(cmd) but also returns the output message captures on
            during the run stdout_file is not None in case of nohup process writes its
            results into a file
            """
            cmd = list(map(str, cmd))  # all items should be string
            if stdout_file is None:
                p = Popen(cmd, stdout=PIPE, stderr=PIPE)
            else:
                with open(stdout_file, "w") as outfile:
                    # output written into file, error will be returned
                    p = Popen(cmd, stdout=outfile, stderr=PIPE, universal_newlines=True)
                    output, error = p.communicate()
                    p.wait()
                    return p, output, error
        
            output, error = p.communicate()
            output = output.strip().decode("utf-8")
            error = error.decode("utf-8")
            return p, output, error
        
        
        def run(cmd):
            log_file = "/tmp/log.txt"
            # if log_file is not provided returned output will be stored in output
            p, output, error_msg = popen_communicate(cmd, log_file)
            if p.returncode != 0:
                raise BashCommandsException(p.returncode, output, error_msg, str(cmd))
            return output
        
        
        if __name__ == "__main__":
            # This could be any command you want to execute as you were in bash
            cmd = ["bash", "script_to_run.sh"]
            try:
                run(cmd)
            except Exception as e:
                print(e)
        
        

        【讨论】:

          猜你喜欢
          • 2020-02-10
          • 2012-05-26
          • 2021-12-07
          • 2023-01-11
          • 2023-03-07
          • 2014-11-12
          • 2011-12-10
          相关资源
          最近更新 更多