[英]Subprocess module from python fails to run bash commands like “<cmd1> | <cmd2>”
The following python script: 以下python脚本:
#!/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
). 它运行正常(输出为
Hello
)。 But when I use subprocess
module this one: 但是当我使用
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)
is not ok. 不好。 The output is
Hello world | cut -d' ' -f1
输出是
Hello world | cut -d' ' -f1
Hello world | cut -d' ' -f1
and I expect to be only Hello
. Hello world | cut -d' ' -f1
,我希望只有Hello
。 How can I correct it? 我该如何纠正?
I saw that in general subprocess module will fail when I'm using a bash command like: 我看到在一般的子流程模块中,当我使用bash命令时会失败:
<cmd1> | <cmd2>
This: 这个:
echo Hello world | cut -d' ' -f1
… is not actually a command, it's a fragment of shell script. ……实际上不是命令,而是shell脚本的一部分。 So you need to have the shell execute it.
因此,您需要让Shell执行它。
You can do this just by adding shell=True
to the Popen
constructor. 您可以通过将
shell=True
添加到Popen
构造函数中来执行此操作。
The documentation explains how this works. 该文档解释了它是如何工作的。 It also explains better ways to do the same thing without the shell .
它还说明了不用shell即可执行相同操作的更好方法 。 For example:
例如:
p1 = Popen(['echo', 'Hello', 'world'], stdout=PIPE)
p2 = Popen(['cut', "-d' '", '-f1'], stdin=p1.stdout, stdout=PIPE)
p1.stdout.close()
test = p2.communicate()[0]
Meanwhile, you almost never want to use split
on a command line—and in fact, your example shows exactly why you don't want to: 同时,您几乎从不希望在命令行上使用
split
实际上,您的示例准确地说明了为什么您不想这样做:
>>> cmd = "echo Hello world | cut -d' ' -f1"
>>> cmd.split()
['echo', 'Hello', 'world', '|', 'cut', "-d'", "'", '-f1']
Notice that it split -d' '
into two arguments, -d'
and '
. 请注意,它将
-d' '
分为两个参数-d'
和'
。
If you're using shell=True
, don't try to split the arguments at all; 如果您使用的是
shell=True
,请不要尝试拆分所有参数。 just pass a string as your cmd
: 只需传递一个字符串作为您的
cmd
:
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True)
If you're not using the shell, the right way to do this is with the shlex
module: 如果您不使用外壳,则正确的方法是使用
shlex
模块:
>>> shlex.split(cmd)
['echo', 'Hello', 'world', '|', 'cut', '-d ', '-f1']
Notice that the "-d' '"
turned into "-d "
this time. 注意,这次
"-d' '"
变成了"-d "
。 That may seem odd at first glance, but it's in fact exactly what the shell would do, and what you want; 乍一看似乎很奇怪,但实际上这正是Shell会做什么以及您想要什么。 the
cut
program will get a space as its d
option. cut
程序将获得一个空格作为其d
选项。 (In other words, the quotes are for the shell, not for the program the shell runs.) (换句话说,引号用于shell,而不是用于shell运行的程序。)
(The shlex
module also has a handle quote
function that you can use for the exact opposite purpose: building a command line from a list of arguments for shell=True
.) (
shlex
模块还具有一个句柄quote
功能,您可以将其用于恰恰相反的用途:从shell=True
的参数列表构建命令行。)
However, it's usually better to just create an list of arguments in the first place, instead of trying to figure out how to create a string that, when run through shlex.split()
, will give you the list you wanted. 但是,通常最好首先创建一个参数列表,而不是试图弄清楚如何创建一个字符串,当通过
shlex.split()
运行该字符串时,它将为您提供所需的列表。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.