python - 来自 python 的子进程模块无法运行 bash 命令,如 "<cmd1> | <cmd2>"

标签 python bash shell

以下 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> 

最佳答案

这个:

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 "。乍一看这似乎很奇怪,但实际上这正是 shell 会做的,也是您想要的; cut 程序将获得一个空格作为其 d 选项。 (换句话说,引号是针对 shell,而不是针对 shell 运行的程序。)

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

但是,通常最好首先创建一个参数列表,而不是试图弄清楚如何创建一个字符串,当运行 shlex.split() 时,将给你你想要的列表。

关于python - 来自 python 的子进程模块无法运行 bash 命令,如 "<cmd1> | <cmd2>",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18411725/

相关文章:

python - iplot 奇怪的连接 Y 轴

python - 时间序列数据的滑动窗口

linux - 新的 bash 命令有命名约定吗?

postgresql - 使用 WShell.Script Run 启动批处理文件时 VBScript 挂起

shell - printf 格式字符串中的变量插值与替换

python - 使用随机库在 python 中生成随机整数失败

python - SqlAlchemy - 外部表中的多态鉴别器

regex - bash 为什么我的正则表达式不起作用?

bash - 重新排列文件中的数据(不是直接转置)

regex - 从这么多文件的开头删除数字的最快方法是什么?