CompletedProcess from subprocess.run () не возвращает строку

Согласно документам Python 3.5 , subprocess.run () возвращает объект CompletedProcess с элементом stdout, который содержит «байтовую последовательность» или строку, если run () вызывается с универсальным_newlines = True ». Я вижу только последовательность байтов, а не строку, которую я предполагал (надеялся), был бы эквивалентен текстовой строке. Например,

import pprint import subprocess my_data = "" line_count = 0 proc = subprocess.run( args = [ 'cat', 'input.txt' ], universal_newlines = True, stdout = subprocess.PIPE) for text_line in proc.stdout: my_data += text_line line_count += 1 word_file = open('output.txt', 'w') pprint.pprint(my_data, word_file) pprint.pprint(line_count, word_file) 

Примечание: здесь используется новая функция в Python 3.5, которая не будет работать в предыдущих версиях.

Нужно ли мне создавать собственную логику буферизации строк, или есть способ заставить Python сделать это для меня?

proc.stdout уже является строкой в ​​вашем случае, запустите print(type(proc.stdout)) , чтобы убедиться. Он содержит весь вывод subprocess.run()subprocess.run() не возвращается, пока дочерний процесс не будет мертв.

for text_line in proc.stdout: неверно: for char in text_string перечисляет символы (Unicode codepoints) в Python, а не в строках. Чтобы получить строки, звоните:

 lines = result.stdout.splitlines() 

Результат может отличаться от .split('\n') если в строке есть строки Unicode.

Если вы хотите прочитать вывод строки за строкой (чтобы избежать нехватки памяти для длительных процессов):

 from subrocess import Popen, PIPE with Popen(command, stdout=PIPE, universal_newlines=True) as process: for line in process.stdout: do_something_with(line) 

Примечание: process.stdout является process.stdout объектом в этом случае. Popen() не дожидался завершения процесса – Popen() возвращается сразу же после запуска дочернего процесса. process – это subprocess.Popen экземпляр, а не CompletedProcess здесь.

Если вам нужно всего лишь подсчитать количество строк (завершенных буквой b'\n' ) на выходе, например wc -l :

 from functools import partial with Popen(command, stdout=PIPE) as process: read_chunk = partial(process.stdout.read, 1 << 13) line_count = sum(chunk.count(b'\n') for chunk in iter(read_chunk, b'')) 

См. Почему чтение строк из stdin происходит намного медленнее на C ++, чем Python?

если вам нужно иметь строки STDOUT в массиве, чтобы лучше их манипулировать, вы просто пропускаете разделение вывода разделителями «Универсальная новая линия»

 nmap_out = subprocess.run(args = ['nmap', '-T4', '-A', '192.168.1.128'], universal_newlines = True, stdout = subprocess.PIPE) nmap_lines = nmap_out.stdout.splitlines() print(nmap_lines) 

выход:

 ['Starting Nmap 7.01 ( https://nmap.org ) at 2016-02-28 12:24 CET', 'Note: Host seems down. If it is really up, but blocking our ping probes, try -Pn', 'Nmap done: 1 IP address (0 hosts up) scanned in 2.37 seconds'] 

Вы видите строку, сравните:

 import subprocess proc = subprocess.run( args = [ 'cat', 'input.txt' ], universal_newlines = False, stdout = subprocess.PIPE) print (type(proc.stdout)) 

class 'bytes'

запускать вызовы popen.communicate

communication () возвращает кортеж (stdout_data, stderr_data). Данные будут байтами или, если universal_newlines имеет значение True, строки.

Посмотрите здесь, чтобы получить больше объяснений и другие взаимодействия с оболочкой.