According to the Python 3.5 docs, subprocess.run() returns an a CompletedProcess object with a stdout member that contains "A bytes sequence, or a string if run() was called with universal_newlines=True." I'm only seeing a byte sequence and not a string, which I was assuming (hoping) would be equivalent to a text line. For example,
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)
Note: this uses a new feature in Python 3.5 that won't run in previous versions.
Do I need to create my own line buffering logic, or is there a way to get Python to do that for me?
To capture the output of the subprocess. run method, use an additional argument named “capture_output=True”. You can individually access stdout and stderr values by using “output. stdout” and “output.
Popen Function The function should return a pointer to a stream that may be used to read from or write to the pipe while also creating a pipe between the calling application and the executed command. Immediately after starting, the Popen function returns data, and it does not wait for the subprocess to finish.
subprocess. check_call() gets the final return value from the script, and 0 generally means "the script completed successfully".
Subprocess allows you to call external commands and connect them to their input/output/error pipes (stdin, stdout, and stderr). Subprocess is the default choice for running commands, but sometimes other modules are better.
proc.stdout
is already a string in your case, run print(type(proc.stdout))
, to make sure. It contains all subprocess' output -- subprocess.run()
does not return until the child process is dead.
for text_line in proc.stdout:
is incorrect: for char in text_string
enumerates characters (Unicode codepoints) in Python, not lines. To get lines, call:
lines = result.stdout.splitlines()
The result may be different from .split('\n')
if there are Unicode newlines in the string.
If you want to read the output line by line (to avoid running out of memory for long-running processes):
from subrocess import Popen, PIPE
with Popen(command, stdout=PIPE, universal_newlines=True) as process:
for line in process.stdout:
do_something_with(line)
Note: process.stdout
is a file-like object in this case. Popen()
does not wait for the process to finish -- Popen()
returns immidiately as soon as the child process is started. process
is a subprocess.Popen
instance, not CompletedProcess
here.
If all you need is to count the number of lines (terminated by b'\n'
) in the output, like 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''))
See Why is reading lines from stdin much slower in C++ than Python?
if you need to have STDOUT lines in an array to better manipulate them you simply miss to split output by the "Universal newline" separators
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)
output is:
['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']
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With