2013-08-14 1 views
24

Я хочу запустить утилиту подсчета слов в Linux wc, чтобы определить количество строк в настоящее время в каталоге/var/log/syslog, поэтому я могу обнаружить, что он растет. Я пробовал различные тесты, и пока я возвращаю результаты из wc, он включает в себя как количество строк, так и команду (например, var/log/syslog).Выход подпроцесса Python3

Так что возвращается: 1338/вар/Журнал/системный журнал Но я хочу только количество строк, поэтому я хочу, чтобы сдирать/вар/войти часть/системного журнала, и просто держать 1338.

I попытались преобразовать его в строку из байта, а затем лишить результат, но не радость. Такая же история для преобразования в строку и снятие, декодирование и т. Д. - все не дают результат, который я ищу.

Вот некоторые примеры того, что я получаю, с 1338 строк в системный журнал:

  • b'1338/вар/Журнал/системного журнала \ п»
  • 1338/вар/Журнал/Syslog

Здесь нет какой-то тестовый код, который я написал, чтобы попытаться взломать эту гайку, но не решение:

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

выход из этого:

  • 2A stdoutdata: b'1338/вар/Журнал/системного журнала \ N»

  • 2B stdoutdata: 1338/VAR/Журнал/системный журнал

  • 2C stdoutdata: 1338/уаг/журнал/системный журнал

  • 2D stdoutdata: 1338/вар/журнал/Syslog

ответ

39

Я предлагаю что вы используете subprocess.getoutput(), так как он делает именно то, что вы хотите, - запустите команду в оболочке и получите ее string output (в отличие от вывода byte string). Затем вы можете split on whitespace и захватить первый элемент из возвращаемого списка строк.

Попробуйте это:

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

Спасибо! Протестировано, и это сработало. Проделал много исследований, никогда не видел этого. Dang! – user2565677

+3

Вы должны быть предупреждены о том, что 'subprocess.getoutput' относится к категории * Legacy Shell Invocation Functions * (http://docs.python.org/3/library/subprocess.html#subprocess.getoutput). – pepr

+0

@pepr Но что означает «наследие», говоря на самом деле? Я не вижу временной шкалы для удаления, начиная с 3.5.0a0. (Может быть определено в другом месте?) – belacqua

8

Чтобы избежать вызова оболочки, и декодирования имен файлов, которые могут быть произвольной последовательности байтов (кроме '\0') на * NIX, вы можете передать файл как стандартный ввод:

import subprocess 

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

Или вы можете игнорировать ошибки декодирования:

import subprocess 

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

Есть ли способ получить 'sys.stdout.encoding' в этом случае, чтобы передать это для декодирования вместо' ascii'? Что делать, если мы 'subprocess.PIPE' stdout? –

+1

@Mr_and_Mrs_D было бы неправильным: 1) это не поможет в общем случае (имя файла может быть байтовой последовательностью, которая не разрешена какой-либо кодировкой символов, поскольку она явно указана в ответе). См. PEP 383) 2-ascii работает здесь (чтобы декодировать цифры, напечатанные wc в любой локали, поддерживаемой Python) – jfs