以下python脚本:
#!/usr/bin/env python
import os
cmd = "echo Hello world | cut -d' ' -f1"
test=os.system(cmd)
print(test)
运行正常(输出为Hello
)。但是当我使用subprocess
模块这个时:
#!/usr/bin/env python
import subprocess
cmd = "echo Hello world | cut -d' ' -f1"
process = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
test = process.communicate()[0]
print (test)
不行。输出为Hello world | cut -d' ' -f1
,我希望只有Hello
。我该如何纠正?
我看到一般情况下,当我使用bash命令时,子进程模块会失败:
<cmd1> | <cmd2>
答案 0 :(得分:6)
此:
echo Hello world | cut -d' ' -f1
...实际上不是命令,它是shell脚本的一个片段。所以你需要让shell执行它。
您只需将shell=True
添加到Popen
构造函数即可。
The documentation解释了这是如何工作的。它还解释了better ways to do the same thing without the shell。例如:
p1 = Popen(['echo', 'Hello', 'world'], stdout=PIPE)
p2 = Popen(['cut', "-d' '", '-f1'], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()
test = p2.communicate()[0]
与此同时,您几乎不想在命令行上使用split
- 实际上,您的示例正好显示您不希望的原因:
>>> cmd = "echo Hello world | cut -d' ' -f1"
>>> cmd.split()
['echo', 'Hello', 'world', '|', 'cut', "-d'", "'", '-f1']
请注意,它将-d' '
分为两个参数-d'
和'
。
如果您正在使用shell=True
,请不要尝试拆分参数;只需将字符串作为cmd
:
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
如果你不使用shell,正确的方法是使用shlex
模块:
>>> shlex.split(cmd)
['echo', 'Hello', 'world', '|', 'cut', '-d ', '-f1']
请注意,这次"-d' '"
变为"-d "
。乍一看这看起来很奇怪,但事实上它确实是外壳会做什么,以及你想要什么; cut
程序会获得一个空格作为d
选项。 (换句话说,引号是针对shell的,而不是针对shell运行的程序。)
(shlex
模块还有一个句柄quote
函数,您可以将其用于完全相反的目的:从shell=True
的参数列表构建命令行。)
但是,通常最好只创建一个参数列表,而不是试图弄清楚如何创建一个字符串,当通过shlex.split()
运行时,它将为您提供所需的列表。