2010-03-22 3 views
13

Ich versuche subprocess.Popen zu verwenden, um eine Sequenz zu erstellen, um die Dauer einer Videodatei zu erfassen. Ich habe für 3 Tage suchen, und kann keinen Grund online als finden, warum dieser Code nicht funktioniert, aber es hält mir ein leeres Ergebnis geben:Richtig Subprocess.PIPE in Python verwenden?

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() 
+5

Warum Sie grep verwenden, schneiden und sed die Ausgabe statt mit eingebauten Python-Funktionen zu analysieren? –

+1

[subprocess.PIPE] (http://thraxil.org/users/anders/posts/2008/03/13/Subprocess-Hanging-PIPE-is-your-enemy/) ist dein Feind – ldgorman

Antwort

14

stderr muss auf stdout umgeleitet werden. Auch gibt keine Notwendigkeit, andere Werkzeuge zu nennen wie cut/sed usw. in Python Ihre String-Manipulation tun

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] 

Wenn Python kein Muss ist, können Sie die Schale direkt verwenden.

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

Danke. Ich wusste nicht, dass ich 'stderr' auch umleiten musste. –

13

subprocess.PIPE Verwendung wird nicht auf magische Weise des Draht richtige Rohre für Sie.

Sie müssen die Ausgangsleitung des ersten Prozesses als Wert für den Parameter stdin des zweiten Prozesses übergeben. See the docs for an example.

4

Python kann auf diese Weise nicht "eine ganze Pipeline" erstellen - es könnte die Aufgabe an die Shell delegieren oder es direkter mit den Attributen stdout früherer Subprozessobjekte in der Zeile kleben, aber es gibt wirklich keine Grund dafür in diesem speziellen Fall, da Sie es ziemlich einfach in Python direkt codieren können. Zum Beispiel:

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 
23

Wie andere darauf hingewiesen haben, müssen Sie die PIPE von einem Prozess zum nächsten weitergeben. Der Stdout (PIPE) von einem Prozess wird zur Standardeingabe für die folgende Aufgabe.

So etwas wie diese (ab Ihrem Beispiel):

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() 
+3

Ich würde dies als die richtige Antwort betrachten, es beantwortet genau das, was OP gefragt hat und sagt nicht, wie man es umgehen könnte. – Beli