【问题标题】:How to use `subprocess` command with pipes如何使用带有管道的`subprocess`命令
【发布时间】:2012-10-31 04:49:35
【问题描述】:

我想将subprocess.check_output()ps -A | grep 'process_name' 一起使用。 我尝试了各种解决方案,但到目前为止没有任何效果。有人可以指导我怎么做吗?

【问题讨论】:

标签: python linux subprocess pipe


【解决方案1】:

要将管道与subprocess 模块一起使用,您必须传递shell=True

但是,出于各种原因,这并不是真正可取的,尤其是安全性。相反,分别创建 psgrep 进程,并将输出从一个管道传输到另一个,如下所示:

ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
ps.wait()

但是,在您的特定情况下,简单的解决方案是调用 subprocess.check_output(('ps', '-A')),然后在输出上调用 str.find

【讨论】:

  • +1 用于分离输出/输入以避免使用shell=True
  • 别忘了,错误subprocess.CalledProcessError: Command '('grep', 'process_name')' returned non-zero exit status 1只是表示grep没有找到任何东西,所以这是正常行为。
  • 当我们已经有了输出时,为什么还需要ps.wait()ps.wait.__doc__ 等待子进程终止,但子进程的内容似乎已放入 output 变量中
  • @MakisH 您正在查看string.find,它已被弃用,取而代之的是str.find(即find 对象上的find 方法)。
  • 注意:如果grep 过早死亡; ps 可能会无限期挂起,如果它产生足够的输出来填充其 OS 管道缓冲区(因为您没有在父级中调用 ps.stdout.close())。 Swap the starting order, to avoid it
【解决方案2】:

或者你总是可以在子进程对象上使用通信方法。

cmd = "ps -A|grep 'process_name'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

communicate 方法返回一个标准输出和标准错误的元组。

【讨论】:

  • 我认为使用communicate 比使用wait 更好。 There is 这样的警告:“这将在使用 stdout=PIPE 和/或 stderr=PIPE 时发生死锁,并且子进程会向管道生成足够的输出,从而阻塞等待 OS 管道缓冲区接受更多数据。使用通信()避免这种情况。”
  • 为了澄清 Paolo 上面的评论,警告是等待,而不是交流 - 即这是他说交流更好的原因。
  • python3中ps.communicate()[0]的输出返回一个字节对象。
  • 你正在重塑subprocess.check_output,不是太差,但没有吸引力。正如文档所建议的那样,当库已经提供了在一行代码中处理所有这些管道的高级函数时,您应该避免使用低级 Popen,通常具有更好的边界条件行为。
  • 为什么要将标准错误重定向到STDOUT
【解决方案3】:

请参阅有关使用子流程设置管道的文档:http://docs.python.org/2/library/subprocess.html#replacing-shell-pipeline

我还没有测试过下面的代码示例,但它应该大致是你想要的:

query = "process_name"
ps_process = Popen(["ps", "-A"], stdout=PIPE)
grep_process = Popen(["grep", query], stdin=ps_process.stdout, stdout=PIPE)
ps_process.stdout.close()  # Allow ps_process to receive a SIGPIPE if grep_process exits.
output = grep_process.communicate()[0]

【讨论】:

  • 检查失败后,请参阅下面 Taymon 的答案,了解一些无需乱搞的东西
  • subprocess.check_output 在 Python 2.6.9 中似乎不存在
【解决方案4】:

使用subprocess.run

import subprocess
    
ps = subprocess.run(['ps', '-A'], check=True, capture_output=True)
processNames = subprocess.run(['grep', 'process_name'],
                              input=ps.stdout, capture_output=True)
print(processNames.stdout)

【讨论】:

  • 注意:capture_output 仅适用于 Python 3.7.9 及更高版本。
  • check 是做什么的,capture_output 的目的是什么?
  • @CervEd 这两个都有明确的记录。 capture_output 是选项组合 stdout=supprocess.PIPE, stderr=subprocess.PIPE 的简写,如果子进程未返回成功(零)状态,check=True 将引发错误。
  • @tripleee 他们被记录在笨拙的 Python 文档中,但答案中没有详细说明为什么包含它们。例如,check=True 不是绝对必要的,但capture_output=True 是为了解决问题。使用这些选项的原因应包含在答案中
  • python 文档很棒,docs.python.org/3/library/subprocess.html ctrl-f "capture_output"
【解决方案5】:

你可以试试sh.py中的管道功能:

import sh
print sh.grep(sh.ps("-ax"), "process_name")

【讨论】:

  • 链接已失效。
【解决方案6】:

另外,请尝试使用'pgrep' 命令而不是'ps -A | grep 'process_name'

【讨论】:

  • 如果你想得到进程ID,显然
【解决方案7】:

JKALAVIS 解决方案很好,但是我会添加一个改进以使用 shlex 而不是 SHELL=TRUE。下面我正在找出查询时间

#!/bin/python
import subprocess
import shlex

cmd = "dig @8.8.4.4 +notcp www.google.com|grep 'Query'"
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
output = ps.communicate()[0]
print(output)

【讨论】:

  • 为什么 shellx 优于 shell?
  • 这里用的shlex在哪里?
  • 这段代码使用shell=True; shlex 已导入,但被忽略。这里没有任何改进。
【解决方案8】:
command = "ps -A | grep 'process_name'"
output = subprocess.check_output(["bash", "-c", command])

【讨论】:

  • 为什么不使用shell=True 并让它在['sh', '-c'] 前面加上呢?此代码中的任何内容都不需要 bash。 (也就是说,完全避免使用 shell 是更好的做法;这个用例是一个合理的用例,但是一旦参数开始参数化——比如将 process_name 作为参数——安全问题就会出现)。
  • 这很有用,因为您不必拆分字符串,当您引用空格时会变得复杂。
  • 嗯? subprocess.check_output(command, shell=True) 不需要您拆分字符串。 Popen 将任何字符串转换为仅包含该字符串的列表 - 因此,[command] - 因此使用 shell=True 您会在该列表之前获得 ['sh', '-c'],因此您最终会得到 ['sh', '-c', command],这正是您的代码除了sh/bash 的区别外,这里都可以。
  • ...就此而言,如果您确实尝试使用shell=True将字符串拆分为列表以及,则只有该列表的第一个元素将被视为代码;你会得到类似['sh', '-c', 'ps', '-A', '|', 'grep', 'process_name']的东西。这不是一件有用的事情:当以这种方式调用时,shell 运行 ps$0-A$1|,等等......但是因为命令 ps 没有看看$0$1等,所有多余的内容都被忽略了。
  • 如果您阅读Lib/subprocess.py,您会发现subprocess.check_output(["sh", "-c", command])subprocess.check_output(command, shell=True) 之间实际上没有区别。代码简洁明了——这不是一个可以有魔鬼隐藏在某处细节中的地方。
【解决方案9】:

Python 3.5之后还可以使用:

    import subprocess

    f = open('test.txt', 'w')
    process = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE, universal_newlines=True)
    f.write(process.stdout)
    f.close()

命令的执行是阻塞的,输出将在process.stdout中。

【讨论】:

  • 将输出写入文件的修饰是切线的,只会使这一点复杂化。
猜你喜欢
  • 2015-03-08
  • 2016-11-11
  • 1970-01-01
  • 1970-01-01
  • 2014-04-13
  • 1970-01-01
  • 1970-01-01
  • 2015-04-12
相关资源
最近更新 更多