1

The following python script:

#!/usr/bin/env python

import os
cmd = "echo Hello world | cut -d' ' -f1"
test=os.system(cmd)
print(test)

it runs ok (the output is Hello). But when I use subprocess module this one:

#!/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)

is not ok. The output is Hello world | cut -d' ' -f1 and I expect to be only Hello. How can I correct it?

I saw that in general subprocess module will fail when I'm using a bash command like:

<cmd1> | <cmd2> 
4

1 回答 1

6

这个:

echo Hello world | cut -d' ' -f1

… 实际上不是命令,它是 shell 脚本的片段。所以你需要让shell执行它。

您可以通过添加shell=TruePopen构造函数来做到这一点。


文档解释了这是如何工作的。它还解释了在没有 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 "这个时候。乍一看,这可能看起来很奇怪,但实际上这正是 shell 会做的事情,也是你想要的;该cut程序将获得一个空格作为其d选项。(换句话说,引号是针对 shell 的,而不是针对 shell 运行的程序的。)

(该shlex模块还有一个句柄quote函数,您可以将其用于完全相反的目的:从参数列表构建命令行shell=True。)

但是,通常最好首先创建一个参数列表,而不是试图弄清楚如何创建一个字符串,当运行该字符串时shlex.split(),它将为您提供所需的列表。

于 2013-08-23T20:59:10.617 回答