web-dev-qa-db-de.com

Python3-Unterprozessausgabe

Ich möchte das Linux Word Count-Dienstprogramm wc ausführen, um die Anzahl der Zeilen in/var/log/syslog zu ermitteln, so dass ich feststellen kann, dass es wächst. Ich habe verschiedene Tests ausprobiert, und obwohl ich die Ergebnisse von wc zurückbekomme, umfasst dies sowohl die Zeilenzahl als auch den Befehl (z. B. var/log/syslog). 

Also kehrt es zurück: 1338 /var/log/syslogBut Ich möchte nur die Zeilenzählung, also möchte ich den/var/log/syslog-Teil entfernen und nur 1338 behalten.

Ich habe versucht, es aus Bytestring in String umzuwandeln und dann das Ergebnis zu entfernen, aber keine Freude. Dieselbe Geschichte für die Konvertierung in Strings und Stripping, Decodierung usw. - alle erzeugen die gewünschte Ausgabe nicht.

Dies sind einige Beispiele für das, was ich mit 1338 Zeilen in syslog bekomme: 

  • b'1338/var/log/syslog\n '
  • 1338/var/log/syslog

Hier ist ein Testcode, den ich geschrieben habe, um diese Nuss zu knacken, aber keine Lösung:

import subprocess

#check_output returns byte string
stdoutdata = subprocess.check_output("wc --lines /var/log/syslog", Shell=True)
print("2A stdoutdata: " + str(stdoutdata))
stdoutdata = stdoutdata.decode("utf-8")
print("2B stdoutdata: " + str(stdoutdata))    
stdoutdata=stdoutdata.strip()
print("2C stdoutdata: " + str(stdoutdata))    

Die Ausgabe davon ist:

  • 2A stdoutdata: b'1338/var/log/syslog\n '

  • 2B stdoutdata: 1338/var/log/syslog

  • 2C stdoutdata: 1338/var/log/syslog

  • 2D stdoutdata: 1338/var/log/syslog

31
user2565677

Ich schlage vor, dass Sie subprocess.getoutput() verwenden, da es genau das tut, was Sie möchten: Führen Sie einen Befehl in einer Shell aus und rufen Sie die Zeichenfolgenausgabe ab (im Gegensatz zu Byte-Zeichenfolge Ausgabe). Dann können Sie auf Whitespace aufteilen und das erste Element aus der zurückgegebenen Liste von Strings übernehmen.

Versuche dies:

import subprocess
stdoutdata = subprocess.getoutput("wc --lines /var/log/syslog")
print("stdoutdata: " + stdoutdata.split()[0])
53
Joseph Dunn

Um das Aufrufen einer Shell zu vermeiden und Dateinamen zu dekodieren, die eine beliebige Bytefolge (außer '\0') auf * nix sein können, können Sie die Datei als stdin übergeben:

import subprocess

with open(b'/var/log/syslog', 'rb') as file:
    nlines = int(subprocess.check_output(['wc', '-l'], stdin=file))
print(nlines)

Oder Sie könnten Dekodierungsfehler ignorieren:

import subprocess

stdoutdata = subprocess.check_output(['wc', '-l', '/var/log/syslog'])
nlines = int(stdoutdata.decode('ascii', 'ignore').partition(' ')[0])
print(nlines)
10
jfs

Seit Python 3.6 können Sie check_output() eine str anstelle von bytes zurückgeben, indem Sie einen encoding - Parameter angeben:

check_output('wc --lines /var/log/syslog', encoding='UTF-8', Shell=True)
1
Curt J. Sampson

Äquivalent zu Curt J. Sampsons Antwort ist auch diese (es gibt einen String zurück):

subprocess.check_output('wc -l /path/to/your/file | cut -d " " -f1', universal_newlines=True, Shell=True)

von docs:

Wenn Kodierung oder Fehler angegeben werden oder Text wahr ist, werden Dateiobjekte für stdin, stdout und stderr werden mit der angegebenen .__ im Textmodus geöffnet. Kodierung und Fehler oder der Standardwert für io.TextIOWrapper. Das Das Argument universal_newlines entspricht dem Text und wird für .__ bereitgestellt. Rückwärtskompatibilität. Standardmäßig werden Dateiobjekte in binärem .__ geöffnet. Modus.

Etwas Ähnliches, aber etwas komplexer mit subprocess.run ():

subprocess.run(command, Shell=True, check=True, universal_newlines=True, stdout=subprocess.PIPE).stdout

als subprocess.check_output () könnte äquivalent zu subprocess.run () sein.

1
Catalin B.