简体   繁体   English

python的子进程模块无法运行bash命令,例如“ <cmd1> | <cmd2> ”

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM