ImranPatel
ImranPatel

Reputation: 11

Why does the following loop not break - Python?

I am trying to print the results of cmd ping google.com, which should output 9 lines in total then stop.

Pinging google.com [216.58.208.46] with 32 bytes of data:
Reply from 216.58.208.46: bytes=32 time=27ms TTL=55
Reply from 216.58.208.46: bytes=32 time=27ms TTL=55
Reply from 216.58.208.46: bytes=32 time=27ms TTL=55
Reply from 216.58.208.46: bytes=32 time=28ms TTL=55

Ping statistics for 216.58.208.46:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 27ms, Maximum = 28ms, Average = 27ms

After running my script below

import subprocess
from subprocess import Popen, PIPE

proc = subprocess.Popen(['ping','www.google.com'],stdout=subprocess.PIPE)
while True:
  line = proc.stdout.readline()
  if line != '':
    print("line:", line)
  else:
    break

I see the dynamically printed cmd results line by like, however after the last line is printed, my loop carries on printing forever, like the following

line: b'Pinging www.google.com [216.58.208.36] with 32 bytes of data:\r\n'
line: b'Reply from 216.58.208.36: bytes=32 time=27ms TTL=56\r\n'
line: b'Reply from 216.58.208.36: bytes=32 time=26ms TTL=56\r\n'
line: b'Reply from 216.58.208.36: bytes=32 time=27ms TTL=56\r\n'
line: b'Reply from 216.58.208.36: bytes=32 time=26ms TTL=56\r\n'
line: b'\r\n'
line: b'Ping statistics for 216.58.208.36:\r\n'
line: b'    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),\r\n'
line: b'Approximate round trip times in milli-seconds:\r\n'
line: b'    Minimum = 26ms, Maximum = 27ms, Average = 26ms\r\n'
line: b''
line: b''
line: b''
line: b''
line: b''
line: b''
line: b''
line: b''
line: b''
...

I am wondering if my loop is carrying on because of this mysteriuos b character, but where is this b character coming from after line:?

modifying

    print("line:", line)

to

    print("line:", line[1:])

returns

line: b'inging www.google.com [216.58.208.36] with 32 bytes of data:\r\n'
line: b'eply from 216.58.208.36: bytes=32 time=28ms TTL=56\r\n'
line: b'eply from 216.58.208.36: bytes=32 time=29ms TTL=56\r\n'
line: b'eply from 216.58.208.36: bytes=32 time=27ms TTL=56\r\n'

not removing the b character.

How can I fix this?

Upvotes: 1

Views: 147

Answers (3)

Aaron Digulla
Aaron Digulla

Reputation: 328770

Since this is Python, this loop does what you want and is more readable:

for line in proc.stdout:
    print(line)

Upvotes: 0

Serge Ballesta
Serge Ballesta

Reputation: 149155

As you use print() and output begins with b, I assume you are using a Python 3.x. In Python 3.x, a string is made of unicode chars , whereas bytes and bytearrays are made of bytes (8 bits). The initial b just says that line is in fact a bytes object.

Your test should then be either if str(line) != '': or if line != b'':, because '' == b'' returns False because they are objects of different classes.

Upvotes: 0

NDevox
NDevox

Reputation: 4086

replace

if line != '':

with

if line:

After the output is finished it doesn't produce a ''. It is therefore easier to check whether an output equates to True or False.

This works well in Python as empty strings, lists, tuples, dictionaries etc, as well as the number 0 and the value None, all equate to False when used in the above manner.

In regards to the b character, that denotes that what you are receiving is a byte string, instead of a normal string. You can't remove the b using slicing in the same way you can't remove the [] brackets from a list using slicing.

To get rid of the b you'll need to decode your string.

Upvotes: 5

Related Questions