在python中嵌入bash

时间:2010-04-16 09:29:48

标签: python bash interop language-interoperability

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

由于

10 个答案:

答案 0 :(得分:30)

理想的做法:

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')

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

如果您不使用stdout=subprocess.PIPE等,则脚本将直接附加到控制台。如果您有来自ssh的密码提示,这非常方便。因此,您可能希望添加标志来控制是否要捕获stdout,stderr和stdin。

答案 1 :(得分:12)

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

答案 2 :(得分:6)

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")

以前的例子,你基本上得到你想要的东西(但你必须考虑到一些辩证的限制)

答案 3 :(得分:4)

当bash命令很简单并且没有括号,逗号和引号时,

subprocess和os.system()工作正常。 嵌入复杂bash参数的简单方法是在python脚本末尾添加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*

答案 4 :(得分:3)

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

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)

答案 5 :(得分:1)

如前所述,您可以使用os.system();它快速而肮脏,易于使用,适用于大多数情况。它实际上是C系统()函数的映射。

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

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

答案 6 :(得分:0)

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

答案 7 :(得分:0)

您可以将IPython用作shell。在网上搜索: “ipython bash replacement”,或者在这里查看:stackoverflow.com/questions/209470/can-i-use-python-as-a-bash-replacement。 您可以从脚本中调用IPython:

#!/usr/bin/ipython --profile=pysh

答案 8 :(得分:0)

@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)

答案 9 :(得分:-1)

我创建了苏丹来准确解决你想要做的事情。它没有任何外部依赖关系,并试图尽可能轻,并为Bash提供Pythonic接口。

https://github.com/aeroxis/sultan