Wie kommt man Ausgabe von einem externen Befehl kombiniert mit Rohr
Frage
Ich habe Befehl wie diese.
wmctrl -lp | awk '/gedit/ { print $1 }'
Und ich will seine Ausgabe in Python-Skript, ich diesen Code versucht,
>>> import subprocess
>>> proc = subprocess.Popen(["wmctrl -lp", "|","awk '/gedit/ {print $1}"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
>>> proc.stdout.readline()
'0x0160001b -1 6504 beer-laptop x-nautilus-desktop\n'
>>> proc.stdout.readline()
'0x0352f117 0 6963 beer-laptop How to get output from external command combine with Pipe - Stack Overflow - Chromium\n'
>>> proc.stdout.readline()
'0x01400003 -1 6503 beer-laptop Bottom Expanded Edge Panel\n'
>>>
Es scheint mein Code falsch nur wmctrl -lp
ist war auszuführen, und | awk '{print $1}'
weggelassen
erwarte, dass meine Ausgabe möchte 0x03800081
$ wmctrl -lp | awk '/gedit/ {print $1}'
0x03800081
Muss man bitte helfen.
Lösung
Mit shell=True
, sollten Sie eine einzelne Befehlszeile anstelle eines Arrays verwenden, sonst wird Ihre zusätzliche Argumente als Shell-Argumente interpretiert werden. Aus der subprocess
Dokumentation :
Unter Unix mit shell = True: Wenn args ein String ist, es gibt die Befehlsfolge durch den Shell ausführen. Wenn args eine Sequenz ist, das erste Element gibt die Befehlsfolge und alle zusätzlichen Einzelteile werden als zusätzliche Schale Argumente behandelt werden.
So sollte Ihr Anruf sein:
subprocess.Popen("wmctrl -lp | sed /gedit/ '{print $1}'", shell=True, ...
Ich glaube, Sie auch eine unausgewogene Apostroph da drin haben.
Andere Tipps
Da Sie eine Sequenz in für das Programm vorbei, denkt es, dass das Rohr eine ist Argument wmcrtrl
, wie wenn Sie getan haben
wmctrl -lp "|"
und damit das tatsächliche Rohr Betrieb verloren.
es einen einzelnen String machen sollte in der Tat geben Sie das richtige Ergebnis:
>>> import subprocess as s
>>> proc = s.Popen("echo hello | grep e", shell=True, stdout=s.PIPE, stderr=s.PIPE)
>>> proc.stdout.readline()
'hello\n'
>>> proc.stdout.readline()
''
Nach einigen Recherchen habe ich den folgenden Code, die für mich sehr gut funktioniert. Er druckt grundsätzlich sowohl stdout und stderr in Echtzeit. Hoffe, es hilft jemand anderes, der es braucht.
stdout_result = 1
stderr_result = 1
def stdout_thread(pipe):
global stdout_result
while True:
out = pipe.stdout.read(1)
stdout_result = pipe.poll()
if out == '' and stdout_result is not None:
break
if out != '':
sys.stdout.write(out)
sys.stdout.flush()
def stderr_thread(pipe):
global stderr_result
while True:
err = pipe.stderr.read(1)
stderr_result = pipe.poll()
if err == '' and stderr_result is not None:
break
if err != '':
sys.stdout.write(err)
sys.stdout.flush()
def exec_command(command, cwd=None):
if cwd is not None:
print '[' + ' '.join(command) + '] in ' + cwd
else:
print '[' + ' '.join(command) + ']'
p = subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd
)
out_thread = threading.Thread(name='stdout_thread', target=stdout_thread, args=(p,))
err_thread = threading.Thread(name='stderr_thread', target=stderr_thread, args=(p,))
err_thread.start()
out_thread.start()
out_thread.join()
err_thread.join()
return stdout_result + stderr_result
Wenn nötig, ich denke, es ist einfach, die Ausgabe oder Fehler in einer Zeichenfolge zu sammeln und zurück.