【问题标题】:How to make Popen wait so the command finishes?如何让 Popen 等待命令完成?
【发布时间】:2023-04-04 06:16:01
【问题描述】:

目标是在带有 Popen 的 bash shell 中启动命令,然后将该命令的输出传递给变量,但 Popen 应该等到命令完成后再继续,这不会发生。

我尝试使用 call 代替 Popen,但 call 只输出退出代码,这并不理想。 我也尝试使用 wait(),但出现错误。

var1 = Popen(["command | grep 'stuff' | cut -d 'delimiter' -f3"], 
             shell=True, stdout=PIPE,
             universal_newlines=True).communicate()[0].rstrip()
var2 = Popen(["command | grep 'stuff' | cut -d 'delimiter' -f1"], 
             shell=True, stdout=PIPE,
             universal_newlines=True).communicate()[0].rstrip()
print(var1 + var2)

Python 正确打印 var1,但不是 var2,它是 None,因为它没有被任何东西分配,因为命令没有运行或没有时间完成。 直接在终端上运行 var2 命令,和在 python 程序中完全一样,会产生想要的结果,但是当 python 尝试运行它时,它只是跳过它并打印 var1 和 var2,但只显示 var1 字符串,var2 完全忽略。

【问题讨论】:

  • 呃。 communicate() 总是 等待管道结束,在本例中为 cut,以关闭其标准输出;否则,它不可能返回一个值。这个问题是基于一个错误的前提。
  • 当您可以在 Python 本身中执行此操作时,为什么要为 grepcut 使用 shell 管道?这将避免需要shell=True,这几乎是一个等待发生的安全漏洞。
  • ...如果您认为Popen() 在管道仍在运行时返回,您将需要提供一个minimal reproducible example 让我们自己观察这种行为。
  • @DanielPryden,点头shell=True 可以安全使用,如果 OP 将所有动态生成的参数从 shell 解析为代码的参数中移出(['''somecommand "$1" | grep "$2" | cut''', "_", "this-becomes-$1", "this-becomes-$2"],但没有证据表明他们正在这样做。
  • Charles Duffy 有两个 Popen 和两个由这些 Popen 的输出分配的变量。两个Popen都被Python运行后,只打印第一个变量,另一个是None

标签: python subprocess popen


【解决方案1】:

出现AttributeError: 'str' object has no attribute 'wait' 错误是因为communicate() 方法返回了(stdout, stderr) 字符串的元组。 wait()Popen 对象本身的方法。如果您使用communicate(),则无需致电wait(),因为它会为您等待。如果您丢弃对 Popen 对象的唯一引用,您不能调用 wait()

也就是说,您真的需要使用grepcut 来完成这项工作吗?这样的事情可能会更快,并且不太可能包含安全错误:

p = Popen(['command'], stdout=PIPE, universal_newlines=True)
result = []
for line in p.stdout:
    if 'stuff' in line:
        value = line.split('delimiter')[4]
        result.append(value)

【讨论】:

  • 这里的一切都是 true,但我很难将其视为 OP 问题的答案。 (也就是说,我很难看到 OP 的问题在这一点上已经足够明确,以至于完全可以回答)。
  • @CharlesDuffy:同意,但这是试图解决问题的后半部分,'str' object has no attribute 'wait' 错误。
  • 那为什么python会跳过Popen呢?它立即从第二个 Popen 跳转到 print 调用,然后打印第一个 Popen 但不打印第二个。顺便说一句,我尝试直接在终端上运行第二个 popen 的命令,它工作得很好
  • @DonJhoe:您的问题中根本没有print。请创建一个 minimal reproducible example 来演示问题 - 没有它,这里的任何人都可以做的就是猜测。
  • @DanielPryden 刷新页面
【解决方案2】:

您必须将命令作为字符串传递,或者自己将其解析为标记。您需要使用subprocess.run 而不是低级别的Popen。微不足道的

var = subprocess.run("command | grep 'stuff' | cut -d 'delimiter' -f3", 
         shell=True, stdout=PIPE,
         universal_newlines=True).stdout

更好的解决方案是用 Python 代码替换 grepcut,并去掉 shell=True 作为有用的奖励。

var = list()
output = subprocess.run(["command"], stdout=PIPE, universal_newlines=True)
for line in output.stdout.split('\n'):
    if 'stuff' in line:
        var.append(line.split('delimiter')[2])

【讨论】:

  • 这里的一切都是真的,但是它是否解决了 OP 的问题(导致他们认为他们的程序不允许完成的问题)?如果有,怎么做?
  • 好问题。我隐约希望正确地做这件事会消除症状。
猜你喜欢
  • 2012-03-18
  • 2016-03-07
  • 2011-10-20
  • 1970-01-01
  • 2015-07-05
  • 2019-07-07
  • 1970-01-01
  • 2013-04-03
  • 2015-06-13
相关资源
最近更新 更多