在Python中运行bash命令
我想在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.match
、re.sub
、re.search
,虽然我对awk不太熟悉,没法把你的命令翻译过来。