【问题标题】:Properly using subprocess.PIPE in python?在 python 中正确使用 subprocess.PIPE?
【发布时间】:2010-03-22 16:31:27
【问题描述】:

我正在尝试使用subprocess.Popen 构建一个序列来获取视频文件的持续时间。我已经搜索了 3 天,在网上找不到任何关于此代码不起作用的原因,但它一直给我一个空白结果:

import sys
import os
import subprocess

def main():
  the_file = "/Volumes/Footage/Acura/MDX/2001/Crash Test/01 Acura MDX Front Crash.mov"
  ffmpeg = subprocess.Popen(['/opt/local/bin/ffmpeg', '-i', the_file], stdout = subprocess.PIPE, )
  grep = subprocess.Popen(['grep', 'Duration'], stdin = subprocess.PIPE, stdout = subprocess.PIPE, )
  cut = subprocess.Popen(['cut', '-d', ' ', '-f', '4'], stdin = subprocess.PIPE, stdout = subprocess.PIPE, )
  sed = subprocess.Popen(['sed', 's/,//'], stdin = subprocess.PIPE, stdout = subprocess.PIPE, )

  duration = sed.communicate()
  print duration

if __name__ == '__main__':
  main()

【问题讨论】:

  • 为什么要使用 grep、cut 和 sed 来解析输出而不是使用 Python 内置函数?
  • subprocess.PIPE 是你的敌人

标签: python subprocess


【解决方案1】:

正如其他人所指出的,您需要将 PIPE 从一个进程传递到下一个进程。 一个进程的标准输出 (PIPE) 成为以下任务的标准输入。

这样的事情(从你的例子开始):

import sys
import os
import subprocess

def main():
  the_file = "/Volumes/Footage/Acura/MDX/
              2001/Crash Test/01 Acura MDX Front Crash.mov"
  ffmpeg = subprocess.Popen(['/opt/local/bin/ffmpeg', '-i', the_file],
                            stdout = subprocess.PIPE)
  grep = subprocess.Popen(['grep', 'Duration'], 
                          stdin = ffmpeg.stdout, stdout = subprocess.PIPE)
  cut = subprocess.Popen(['cut', '-d', ' ', '-f', '4'],
                         stdin = grep.stdout, stdout = subprocess.PIPE)
  sed = subprocess.Popen(['sed', 's/,//'],
                         stdin = cut.stdout, stdout = subprocess.PIPE)

  duration = sed.communicate()[0]
  print duration

if __name__ == '__main__':
  main()

【讨论】:

  • 我认为这是正确的答案,它准确地回答了 OP 的要求,并没有说明如何解决它。
  • 现在有一个管道模块:docs.python.org/3/library/…
【解决方案2】:

使用subprocess.PIPE 不会神奇地为您连接正确的管道。

您必须将第一个进程的输出管道作为第二个进程的参数stdin 的值传递。 See the docs for an example.

【讨论】:

    【解决方案3】:

    stderr 需要重定向到标准输出。此外,无需调用其他工具(如 cut/sed 等)在 Python 中进行字符串操作

    import subprocess
    ....
    the_file = "/Volumes/Footage/Acura/MDX/2001/Crash Test/01 Acura MDX Front Crash.mov"
    ffmpeg = subprocess.Popen(['/usr/bin/ffmpeg', '-i', the_file], stderr=subprocess.STDOUT,stdout = subprocess.PIPE )
    out, err = ffmpeg.communicate()
    if "Duration" in out:
        print out[out.index("Duration"):].split()[1]
    

    如果Python不是必须的,可以直接使用shell。

    the_file="/Volumes/Footage/Acura/MDX/2001/Crash Test/01 Acura MDX Front Crash.mov"
    ffmpeg -i "$file" 2>&1 | awk '/Duration/{print $2}'
    

    【讨论】:

    • 谢谢。我没有意识到我也必须重定向stderr
    【解决方案4】:

    Python 不能以这种方式“构建整个管道”——它可以将任务委托给 shell,或者使用行中先前子进程对象的 stdout 属性更直接地将其粘合起来,但确实有在这种特定情况下没有理由这样做,因为您可以很容易地直接在 Python 中编写代码。例如:

      ffmpeg = subprocess.Popen(['/opt/local/bin/ffmpeg', '-i', the_file],
                                stdout=subprocess.PIPE)
      for line in ffmpeg.stdout:
        if 'Duration' not in line: continue
        fields = line.split()
        duration = fields[4].replace(',', '')
        break
    

    【讨论】:

      猜你喜欢
      • 2013-01-14
      • 1970-01-01
      • 2013-05-23
      • 1970-01-01
      • 2010-09-27
      相关资源
      最近更新 更多