web-dev-qa-db-ja.com

Pythonでsubprocess.PIPEを適切に使用していますか?

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()
14
Gordon Fontenot

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が必須ではない場合は、シェルを直接使用できます。

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

他の人が指摘しているように、あるプロセスから次のプロセスにPIPEを渡す必要があります。 1つのプロセスからのstdout(PIPE)は、次のタスクのstdinになります。

このようなもの(あなたの例から始めて):

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()
25
KevB

subprocess.PIPEを使用しても、正しいパイプが魔法のように配線されることはありません。

最初のプロセスの出力パイプを、2番目のプロセスのパラメータstdinの値として渡す必要があります。 例についてはドキュメントを参照してください

14
Aaron Digulla

Pythonは、この方法で「パイプライン全体を構築」することはできません。タスクをシェルに委任したり、行の前のサブプロセスオブジェクトの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
4
Alex Martelli