在Python中运行bash命令

0 投票
6 回答
1008 浏览
提问于 2025-04-18 07:32

我想在Python环境中运行一个bash命令。

grep -Po "(?<=<cite>).*?(?=</cite>)" /tmp/file1.txt | awk -F/ '{print $1}' | awk '!x[$0]++' > /tmp/file2.txt

我尝试过的方法是:

#!/usr/bin/python
import commands
commands.getoutput('grep ' + '-Po ' +  '\"\(?<=<dev>\).*?\(?=</dev>\)\" ' + '/tmp/file.txt ' + '| ' + 'awk \'!x[$0]++\' ' + '> ' + '/tmp/file2.txt')

但是我没有得到任何结果。

谢谢你

6 个回答

0

你必须使用

import os 
os.system(command)
0

现在,commands模块已经过时了。

如果你其实不需要命令的输出,可以使用

import os

exit_status = os.system("your-command")

否则,你可以使用

import suproccess

out, err = subprocess.Popen("your | commands", stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell = True).communicate()

注意:在你的命令中,你把标准输出(stdout)发送到了file2.txt,所以我不指望在out中看到任何东西。不过,你仍然会在标准错误(stderr)中看到错误信息,这些信息会进入err

1

让我们写一个简单的函数,来帮我们处理这些复杂的管道操作:

def subprocess_pipes (pipes, last_pipe_out = None):
    import subprocess
    from subprocess  import PIPE
    last_p = None
    for cmd in pipes:
        out_pipe = PIPE if not (cmd==pipes[-1] and last_pipe_out) else open(last_pipe_out, "w")
        cmd = cmd if isinstance(cmd, list) else cmd.split(" ")
        in_pipe = last_p.stdout if last_p else None
        p = subprocess.Popen(cmd, stdout = out_pipe, stdin = in_pipe)
        last_p = p
    comm = last_p.communicate()
    return comm

然后我们运行这个函数,

subprocess_pipes(("ps ax", "grep python"), last_pipe_out = "test.out.2")

结果会生成一个名为 "test.out.2" 的文件,里面的内容是将 "ps ax" 的输出通过管道传递给 "grep python" 的结果。

在你的情况下,

a = ["grep", "-Po", "(?<=<cite>).*?(?=</cite>)", "/tmp/file1.txt"]
b = ["awk", "-F/", "{print $1}"]
c = ["awk", "!x[$0]++"]

subprocess_pipes((a, b, c),  last_pipe_out = "/tmp/file2.txt")
3

在Python中,推荐的方式来运行系统命令是使用一个叫做 subprocess 的模块。

import subprocess

a=['grep' ,'-Po', '"(?<=<dev>).*?(?=</dev>)"','/tmp/file.txt']
b=['awk', '-F/', '"{print $1}"'] 
c=["awk", '"!x[$0]++"']

p1 = subprocess.Popen(a,stdout=subprocess.PIPE)
p2 = subprocess.Popen(b,stdin=p1.stdout,stdout=subprocess.PIPE)
p3 = subprocess.Popen(c,stdin=p2.stdout,stdout=subprocess.PIPE)
p1.stdout.close()
p2.stdout.close()
out,err=p3.communicate()
print out

在每个子进程之间创建管道的目的是出于安全和调试的考虑。此外,这样做可以让代码更清晰,方便理解哪个进程接收输入,哪个进程发送输出。

3

如果你想避免拆分你的参数,也不想担心管道的问题,可以使用 shell=True 这个选项:

cmd = "grep -Po \"(?<=<dev>).*?(?=</dev>)\" /tmp/file.txt | awk -F/ '{print $1}' | awk '!x[$0]++' > file2.txt"
out = subprocess.check_output(cmd, shell=True)

这样会运行一个子shell,它能理解你所有的指令,包括“|”用于管道,和“>”用于重定向。如果不这样做,这些通常由shell解析的符号就会直接传给grep程序。

否则,你就得自己创建管道。例如(下面的代码未经测试):

grep_p = subprocess.Popen(["grep", "-Po", "(?<=<dev>).*?(?=</dev>)", "/tmp/file.txt"], stdout=subprocess.PIPE)
awk_p = subprocess.Popen(["awk", "-F/", "'{print $1}'"], stdin = grep_p.stdout)
file2_fh = open("file2.txt", "w")
awk_p_2 = subprocess.Popen(["awk", "!x[$0]++", stdout = file2_fh, stdin = awk_p.stdout)
awk_p_2.communicate()

不过,如果你这样做的话,就有点偏离python的本意了。你应该看看re模块,比如 re.matchre.subre.search,虽然我对awk不太熟悉,没法把你的命令翻译过来。

撰写回答