2015-12-24 7 views
5

Wenn ich den folgenden CodePython Subprocess kommunizieren() liefert keine, wenn Liste der Zahl wird voraussichtlich

laufen
from subprocess import call, check_output, Popen, PIPE 

gr = Popen(["grep", "'^>'", myfile], stdout=PIPE) 
sd = Popen(["sed", "s/.*len=//"], stdin=gr.stdout) 
gr.stdout.close() 
out = sd.communicate()[0] 
print out 

Wo Meinedat wie folgt aussieht:

>name len=345 
sometexthere 
>name2 len=4523 
someothertexthere 
... 
... 

ich

None 
Wenn die erwartete Ausgabe eine Liste von Zahlen ist:
345 
4523 
... 
... 

Der entsprechende Befehl, den ich im Terminal laufen ist

grep "^>" myfile | sed "s/.*len=//" > outfile 

Bisher habe ich versucht, das Spiel mit Flucht und zitiert in unterschiedlicher Weise, wie Schrägstriche in den sed oder das Hinzufügen von zusätzlichen Anführungszeichen zu entkommen für Grep, aber die kombinatorischen Möglichkeiten sind groß.

Ich habe auch in Erwägung gezogen, nur in der Datei lesen und Python Äquivalente von grep und sed schreiben, aber die Datei ist sehr groß (ich konnte immer Zeile für Zeile lesen), wird es immer auf UNIX-basierten Systemen und ich laufen bin immer noch neugierig, wo ich Fehler gemacht habe.

Könnte es, dass

sd.communicate()[0] 

eine Art von Objekt zurückgibt (anstelle der Liste der ganzen Zahlen), für die keine ist der Typ?

Ich weiß, dass ich die Ausgabe mit check_output in einfachen Fällen greifen:

sam = check_output(["samn", "stats", myfile]) 

aber nicht sicher, wie es mit komplizierteren Situationen machen Arbeit waren Sachen verrohrt werden immer.

Was sind einige produktive Ansätze, um die erwarteten Ergebnisse mit Subprozess zu erhalten?

Antwort

4

Wie vorgeschlagen Sie stdout=PIPE in dem zweiten Prozess müssen und entfernen Sie die einzelne Zitate aus "'^>'":

gr = Popen(["grep", "^>", myfile], stdout=PIPE) 
Popen(["sed", "s/.*len=//"], stdin=gr.stdout, stdout=PIPE) 
...... 

Dies kann aber nur reinen Python getan werden und re:

import re 
r = re.compile("^\>.*len=(.*)$") 
with open("test.txt") as f: 
    for line in f: 
     m = r.search(line) 
     if m: 
      print(m.group(1)) 

Welches würde ausgeben:

345 
4523 

Wenn die Zeilen, die mit > beginnen immer die Nummer haben und die Zahl ist immer am Ende nach len= dann eigentlich Sie kein Regex benötigen entweder:

with open("test.txt") as f: 
    for line in f: 
     if line.startswith(">"): 
      print(line.rsplit("len=", 1)[1]) 
+1

nicht verwenden 'check_output()' hier: es hängen kann 'grep' Prozess, wenn' sed' vorzeitig stirbt (bis gc in der übergeordneten 'gr.stdout' Rohr schließt). Um den Aufruf von .close() 'zu vermeiden, starten Sie rückwärts - siehe [Wie verwende ich subprocess.Popen, um mehrere Prozesse über Pipes zu verbinden?] (Http://stackoverflow.com/a/9164238/4279) – jfs

+0

@JF Sebastian, ich habe es einfach entfernt, da kein Subprozess-Aufruf nötig ist, auch was ist 'gc'? –

+0

Ja, hier ist kein Subprozess notwendig. GC ist Garbage Collection. – jfs

2

Sie benötigen stdout auf Ihrem zweiten Popen Anruf umgeleitet werden oder der Ausgang gehen Sie einfach auf den übergeordneten Prozess stdout und communicate wird None zurück.

sd = Popen(["sed", "s/.*len=//"], stdin=gr.stdout, stdout=PIPE) 
4
  1. Sie einfache Anführungszeichen nicht um ^> in der grep Zeile. Dies ist keine Bash, also werden alle Argumente wörtlich an das zugrundeliegende Programm übergeben.
  2. Sie müssen sd 's stout auf PIPE umleiten.
1

Padraic Cunningham Antwort ist akzeptabel

Wie einfache Anführungszeichen in der Befehlszeile String

use shlex 

anzuwenden.

import shlex 
from subprocess import call, check_output, Popen, PIPE 
gr = Popen(shlex.split("grep '^>' my_file"), stdout=PIPE) 
sd = Popen(["sed", "s/.*len=//"], stdin=gr.stdout,stdout=PIPE) 
gr.stdout.close() 
out = sd.communicate()[0] 
print out