2013-08-14 10 views
24

Ich möchte das Linux-Wortzahl-Dienstprogramm wc ausführen, um die Anzahl der Zeilen zu ermitteln, die sich derzeit im Verzeichnis/var/log/syslog befinden, damit ich feststellen kann, dass es wächst. Ich habe verschiedene Tests ausprobiert, und während ich die Ergebnisse von wc zurückbekomme, enthält es sowohl die Zeilenzählung als auch den Befehl (z. B. var/log/syslog).Python3-Subprozess-Ausgabe

es ist so Rückkehr: 1338/var/log/syslog Aber ich will nur die Zeilenzahl, so möchte ich das Verzeichnis/var/log/syslog Teil abzustreifen, und halten nur 1338

I habe versucht, es in String aus Bytestring zu konvertieren und dann das Ergebnis zu strippen, aber keine Freude. Die gleiche Geschichte für die Umwandlung in Strings und Stripping, Decodierung usw. - alle erzeugen nicht die Ausgabe, nach der ich suche.

Dies sind nur einige Beispiele dafür, was ich bekommen, mit 1338 Zeilen in syslog:

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

Hier einiger Test-Code ich geschrieben habe diese Mutter zu versuchen und 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 von dieser 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

Antwort

39

ich schlage vor, dass Sie subprocess.getoutput() verwenden, da es genau das tut, was Sie wollen - führen Sie einen Befehl in einer Shell aus und rufen Sie string output auf (im Gegensatz zu byte string Ausgabe). Dann können Sie split on whitespace und greifen Sie das erste Element aus der zurückgegebenen Liste von Zeichenfolgen.

Try this:

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

Dank! Getestet, und es hat funktioniert. Hatte viel recherchiert, das nie gesehen. Dang! – user2565677

+3

Sie sollten gewarnt werden, dass der 'subprocess.getoutput' zu der Kategorie * Legacy Shell Invocation Functions * (http://docs.python.org/3/library/subprocess.html#subprocess.getoutput) gehört. – pepr

+0

@pepr Was bedeutet die Bezeichnung "Vermächtnis" praktisch? Ich sehe keine Zeitleiste zum Entfernen, ab 3.5.0a0. (Kann anderswo definiert werden?) – belacqua

8

zu vermeiden, um einen Shell und Decodierung Dateinamen aufgerufen wird, die eine beliebige Byte-Sequenz sein könnte (außer '\0') auf * nichts, 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 keine Decodierungsfehler ignorieren:

import subprocess 

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

Gibt es eine Möglichkeit, die 'sys.stdout.encoding' in diesem Fall zu bekommen, also übergeben wir dies zu dekodieren statt' ascii'? Was ist, wenn wir 'PIPE' stdout? –

+1

@Mr_and_Mrs_D es wäre eine falsche Sache zu tun: 1- Es wird nicht im allgemeinen Fall helfen (ein Dateiname kann eine Byte-Folge sein, die durch eine beliebige Zeichencodierung nicht dekodierbar ist, wie es ausdrücklich in der Antwort gesagt wird. Siehe PEP 383) 2- ascii funktioniert hier (um Ziffern zu dekodieren, die in einem von Python unterstützten Gebietsschema von wc gedruckt wurden) – jfs