【问题标题】:Call a shell commands from python's subprocess continuously and parse the output [duplicate]从python的子进程连续调用shell命令并解析输出[重复]
【发布时间】:2019-02-05 16:26:51
【问题描述】:

我正在开发一个嵌入式应用程序,它使用来自CANBOAT 存储库的一些预编译二进制文件。

有两个二进制文件可供使用:

  1. actisense-serial
  2. analyzer

在 shell 中,需要执行actisense -r /dev/ttyUSB0 | analyzer -json 以从连接到 USB 端口的设备获取信息。上述命令将 JSON 信息转储到 STDOUT。

样本输出:

{"timestamp":"2018-08-30T16:27:23.629Z","prio":2,"src":3,"dst":255,"pgn":128259,"description":"Speed","fields":{"SID":106,"Speed Water Referenced Type":"Paddle wheel"}}

{"timestamp":"2018-08-30T16:27:23.629Z","prio":2,"src":6,"dst":255,"pgn":128259,"description":"Speed","fields":{"SID":106,"Speed Water Referenced Type":"Paddle wheel"}}

上述值一直显示在 STDOUT 上。

我希望在 python 脚本中使用上述 shell 命令来获取 JSON 值,解析它们并将它们保存到数据库中。

最初我想从subprocess.check_output 开始。

我试过了:

import subprocess

if __name_ == "__main__":

     while True:
         value = subprocess.check_output(['actisense-serial -r /ttyUSB0',
                                           '|',
                                           'analyzer -json'],
                                        shell=True)
         print(value)

但是没有可用的输出。我不确定如何将 STDOUT 的输出路由到 check_output

如何实现这一点,来自 shell 命令的连续 JSON 信息可以被解析并在应用程序中进一步使用?

【问题讨论】:

  • 我会先修复命令,使其实际工作,然后再担心流式输出。 shell=True 在此处无法按您期望的方式工作 - 只有第一个列表元素被解析为 shell 脚本。
  • ['''actisense-serial -r "$1" | analyzer -json''', '_', "/ttyUSB0"] 是可与shell=True 一起使用的参数列表示例(第一个列表条目是要运行的shell 脚本,第二个是运行该脚本的$0,第三个是 $1 它运行)。
  • ...实际的连续流式传输是一个单独的问题,我们已经对此进行了问答。
  • *.com/questions/46592284/… 是直接提出问题的 Windows 答案; *.com/questions/2715847/… 是一个更通用的。

标签: python python-3.x subprocess


【解决方案1】:

当您像这样使用Popen 时,您可以将管道传递给stdoutstderr

actisense_proc = subprocess.Popen(['actisense-serial', '-r', '/ttyUSB0'], 
                                  stdout=subprocess.PIPE)
analyzer_proc = subprocess.Popen(['analyzer', '-json'], stdin=actisense_proc.stdout,
                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while analyzer_proc.poll() is None:
    print(analyzer_proc.stdout.readline())

还要注意,我没有使用shell=True,而是使用了两个Popen 调用,并将第一个的标准输出通过管道传输到第二个的stdin

编辑:错过了问题的流媒体部分。已更新,因此它将不断从标准输出管道中读取。这将一直运行到子进程终止。

【讨论】:

  • 这解决了 OP 代码中的另一个问题,但我不相信它与直接提出的问题有关; communicate() 是一次收集所有内容,而不是阅读连续的流,这是问题的具体要求。
  • ...对于这里回答的问题,*.com/questions/10405515/… 是重复的
  • @CharlesDuffy Yikes,完全错过了流媒体部分。