How can I read one line from a telnet response with Python?

mad5245 picture mad5245 · Apr 26, 2013 · Viewed 18.9k times · Source

I was surprised that I couldn't find this question on here.

I would like to take extract one line from a telnet response and make it a variable. (actually one number from that line). I can extract up to where I need using telnet.read_until(), but the whole beginning is still there. The printout shows different statuses of a machine.

The line I am trying to get is formatted like this:

CPU Utilization          : 5 %

I really only need the number, but there are many ':' and '%' characters in the rest of the output. Can anyone help me extract this value? Thanks in advance!

Here is my code (this reads the whole output and prints):

import telnetlib, time


print ("Starting Client...")
host    = input("Enter IP Address: ")
timeout = 120

print ("Connecting...")
try:
    session = telnetlib.Telnet(host, 23, timeout)
except socket.timeout:
    print ("socket timeout")
else:
    print("Sending Commands...")
    session.write("command".encode('ascii') + b"\r")
    print("Reading...")
    output = session.read_until(b"/r/n/r/n#>", timeout )
    session.close()
    print(output)
    print("Done")

Edit: some example of what an output could be:

Boot Version         : 1.1.3 (release_82001975_C)
Post Version         : 1.1.3 (release_82001753_E)
Product VPD Version  : release_82001754_C
Product ID           : 0x0076
Hardware Strapping   : 0x004C
CPU Utilization      : 5 %
Uptime               : 185 days, 20 hours, 31 minutes, 29 seconds
Current Date/Time    : Fri Apr 26 17:50:30 2013

Answer

abarnert picture abarnert · Apr 26, 2013

As you say in the question:

I can extract up to where I need using telnet.read_until(), but the whole beginning is still there.

So you can get all of the lines up to and including the one you want into a variable output. The only thing you're missing is how to get just the last line in that output string, right?

That's easy: just split output into lines and take the last one:

output.splitlines()[:-1]

Or just split off the last line:

output.rpartition('\n')[-1]

This doesn't change output, it's just an expression that computes a new value (the last line in output). So, just doing this, followed by print(output), won't do anything visibly useful.

Let's take a simpler example:

a = 3
a + 1
print(a)

That's obviously going to print 3. If you want to print 4, you need something like this:

a = 3
b = a + 1
print(b)

So, going back to the real example, what you want is probably something like this:

line = output.rpartition('\n')[-1]
print(line)

And now you'll see this:

CPU Utilization          : 5 %

Of course, you still need something like Johnny's code to extract the number from the rest of the line:

numbers = [int(s) for s in line.split() if s.isdigit()]
print(numbers)

Now you'll get this:

['5']

Notice that gives you a list of one string. If you want just the one string, you still have another step:

number = numbers[0]
print(number)

Which gives you:

5

And finally, number is still the string '5', not the integer 5. If you want that, replace that last bit with:

number = int(numbers[0])
print(number)

This will still print out 5, but now you have a variable you can actually use as a number:

print(number / 100.0) # convert percent to decimal

I'm depending on the fact that telnet defines end-of-line as \r\n, and any not-quite-telnet-compatible server that gets it wrong is almost certainly going to use either Windows-style (also \r\n) or Unix-style (just \n) line endings. So, splitting on \n will always get the last line, even for screwy servers. If you don't need to worry about that extra robustness, you can split on \r\n instead of \n.


There are other ways you could solve this. I would probably either use something like session.expect([r'CPU Utilization\s*: (\d+)\s*%']), or wrap the session as an iterator of lines (like a file) and then just do write the standard itertools solution. But this seems to be simplest given what you already have.