在python中正确使用subprocess.PIPE?

时间:2010-03-22 16:31:28

标签: python subprocess

我正在尝试使用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()

4 个答案:

答案 0 :(得分:24)

正如其他人所指出的,您需要将PIPE从一个进程传递到下一个进程。 来自一个进程的stdout(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()

答案 1 :(得分:15)

stderr需要重定向到stdout。此外,没有必要调用其他工具,如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}'

答案 2 :(得分:13)

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

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

答案 3 :(得分:4)

Python不能以这种方式“构建整个管道” - 它可以将任务委托给shell,或者使用行中先前子进程对象的stdout属性直接粘贴它,但是在这种特定情况下,实际上没有理由这样做,因为你可以很容易地直接用Python编写代码。 E.g:

  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