2013-08-14 13 views
24

Sto cercando di eseguire il programma di conteggio delle parole di Linux wc per determinare il numero di righe attualmente in/var/log/syslog, così posso rilevare che sta crescendo. Ho provato vari test, e mentre ottengo i risultati da wc, include sia il conteggio delle righe che il comando (ad es. Var/log/syslog).Output subprocess Python3

Quindi è il ritorno: 1338/var/log/syslog Ma io voglio solo il numero di linee, quindi voglio togliere il/var/log porzione/syslog, e tenere solo 1338.

I ho provato a convertirlo in stringa da bytestring, e quindi a rimuovere il risultato, ma senza gioia. Stessa storia per la conversione in stringa e stripping, decodifica, ecc. - non tutti producono l'output che sto cercando.

Questi sono alcuni esempi di quello che mi capita, con 1338 linee in syslog:

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

Ecco alcuni codice di prova che ho scritto per cercare di rompere il dado, ma nessuna soluzione:

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))  

L'output di questo è:

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

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

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

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

risposta

39

suggerisco che usi subprocess.getoutput() come fa esattamente quello che vuoi: esegui un comando in una shell e ottieni il suo string output (a differenza dell'output byte string). Quindi puoi split on whitespace e prendere il primo elemento dall'elenco di stringhe restituito.

Prova questo:

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

Grazie! Testato, e ha funzionato. Aveva fatto molte ricerche, mai visto. Dang! – user2565677

+3

Si dovrebbe essere avvisati che 'subprocess.getoutput' appartiene alla categoria di * Funzioni di Invocazione shell legacy * (http://docs.python.org/3/library/subprocess.html#subprocess.getoutput). – pepr

+0

@pepr Ma cosa significa la designazione "legacy", in pratica? Non vedo una sequenza temporale per la rimozione, a partire da 3.5.0a0. (Può essere definito altrove?) – belacqua

8

Per evitare di invocare una shell e decodifica i nomi dei file che potrebbero essere una sequenza di byte arbitraria (eccetto '\0') su * nix, potreste passare il file come standard input:

import subprocess 

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

Oppure si potrebbe ignorare eventuali errori di decodifica:

import subprocess 

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

C'è un modo per ottenere 'sys.stdout.encoding' in questo caso, quindi passiamo questo a decodificare invece di 'ascii'? Cosa succede se abbiamo lo stdout "sottoprocesso.PIPE"? –

+1

@Mr_and_Mrs_D sarebbe una cosa sbagliata: 1- non sarà d'aiuto nel caso generale (un nome di file può essere una sequenza di byte che non può essere decodificata da alcuna codifica di caratteri come viene esplicitamente indicata nella risposta.) Vedi PEP 383) 2- ascii funziona qui (per decodificare le cifre stampate da wc in qualsiasi locale supportata da Python) – jfs