如何在管道中使用`subprocess`命令

zub*_*ber 214 python linux subprocess pipe

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

Tay*_*mon 394

要使用带subprocess模块的管道,您必须通过shell=True.

但是,由于各种原因,这并不是真的可取,尤其是安全性.相反,单独创建psgrep处理,并将输出从一个管道传输到另一个,如下所示:

ps = subprocess.Popen(('ps', '-A'), stdout=subprocess.PIPE)
output = subprocess.check_output(('grep', 'process_name'), stdin=ps.stdout)
ps.wait()
Run Code Online (Sandbox Code Playgroud)

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

  • +1用于分隔输出/输入以避免使用`shell = True` (73认同)
  • 不要忘记,错误```subprocess.CalledProcessError:Command'('grep','process_name')'返回非零退出状态1```只是意味着grep找不到任何内容,所以这是正常的行为. (3认同)
  • @MakisH您正在查看`string.find`,它已被弃用,转而使用`str.find`(即`str`对象的`find`方法). (3认同)
  • 注意:如果`grep`过早死亡; 如果它产生足够的输出来填充其OS管道缓冲区(因为你没有在父级中调用`ps.stdout.close()`,`ps`可能会无限期挂起.[交换起始顺序,以避免它](http://stackoverflow.com/a/9164238/4279) (3认同)
  • 当我们已经有输出时,为什么我们需要`ps.wait()`.`ps.wait .__ doc__`等待孩子终止,但孩子的内容似乎已经放入`output`变量 (2认同)

jka*_*vas 51

或者,您始终可以在子进程对象上使用communic方法.

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

communic方法返回标准输出的元组和标准错误.

  • 为了澄清 Paolo 上面的评论,警告是为了等待,而不是为了交流——也就是说,这就是他说交流更好的原因。 (5认同)
  • 我认为使用`communic`比`wait`更好.[有](https://docs.python.org/2/library/subprocess.html#subprocess.Popen.wait)这样的警告:"当使用stdout = PIPE和/或stderr = PIPE和孩子时,这会死锁进程为管道生成足够的输出,以阻止等待OS管道缓冲区接受更多数据.使用communic()来避免这种情况." (3认同)

Alc*_*ive 21

请参阅有关使用子流程设置管道的文档: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]
Run Code Online (Sandbox Code Playgroud)

  • 检查失败后,请查看Taymon的以下答案,以解决一些无法解决的问题 (2认同)
  • subprocess.check_output似乎不存在于Python 2.6.9中 (2认同)

ana*_*n78 14

使用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)
Run Code Online (Sandbox Code Playgroud)

  • @CervEd 这两个都清楚地记录在案。`capture_output` 是选项组合 `stdout=supprocess.PIPE, stderr=subprocess.PIPE` 和 `check=True` 的简写,如果子进程没有返回成功(零)状态,则会引发错误。 (4认同)
  • 注意:“capture_output”仅适用于 Python 3.7.9 及更高版本。 (3认同)
  • 这种方法的一个缺点是“capture_output”会将进程的所有标准输出读入内存。对于像 ps 这样的小程序,这可能没问题,但对于较大的分析管道,应该避免这样做。 (3认同)
  • `check` 的作用是什么?`capture_output` 的目的是什么? (2认同)
  • @tripleee 它们被记录在笨重的 Python 文档中的某个地方,但答案中没有详细说明为什么包含它们。例如,“check=True”并不是严格必要的,但“capture_output=True”是为了使答案起作用。使用这些选项的原因应包含在答案中 (2认同)

Sho*_*ooe 5

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

  • 如果你想获得进程ID,显然 (2认同)

小智 5

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)
Run Code Online (Sandbox Code Playgroud)

  • shlex在这里用在哪里? (7认同)
  • 这段代码_is_使用 `shell=True`; shlex 已导入,但被忽略。这里没有任何改进。 (4认同)