How to catch a line with Popen
Chris Torek
nospam at torek.net
Sun May 29 21:02:41 EDT 2011
In article <irtj2o$h0m$1 at speranza.aioe.org>
TheSaint <nobody at nowhere.net.no> wrote:
>Chris Rebert wrote:
>I just suppose to elaborate the latest line, as soon it's written on the
>pipe, and print some result on the screen.
>Imaging something like
>
> p= Popen(['ping','-c40','www.google.com'], stdout=PIPE)
> for line in p.stdout:
> print(str(line).split()[7])
>
>I'd like to see something like *time=54.4*
>This is just an example, where if we remove the "-c40" on the command line,
>I'd expect to read the latest line(s), until the program will be killed.
In at least some versions of Python 2, file-like object "next"
iterators do not "work right" with unbuffered (or line-buffered)
pipe-file-objects. (This may or may not be fixed in Python 3.)
A simple workaround is a little generator using readline():
def line_at_a_time(fileobj):
"""
Return one line at a time from a file-like object.
Works around the iter behavior of pipe files in
Python 2.x, e.g., instead of "for line in file" you can
write "for line in line_at_a_time(file)".
"""
while True:
line = fileobj.readline()
if not line:
return
yield line
Adding this to your sample code gives something that works for me,
provided I fiddle with it to make sure that the only lines
examined are those with actual ping times:
p = subprocess.Popen(["ping", "-c5", "www.google.com"],
stdout = subprocess.PIPE)
for lineno, line in enumerate(line_at_a_time(p.stdout)):
if 1 <= lineno <= 5:
print line.split()[6]
else:
print line.rstrip('\n')
p.wait() # discard final result
(Presumably the enumerate() trick would not be needed in whatever
you really use.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: gmail (figure it out) http://web.torek.net/torek/index.html
More information about the Python-list
mailing list