Question

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
Was it helpful?

Solution

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.

OTHER TIPS

As I understand the problem, you want to select 1 line out of a block of lines, but not necessarily the last line.

The line you're interested in always starts with "CPU Utilization"

This should work:

for line in output.splitlines():
  if 'CPU Utilization' in line:
    cpu_utilization = line.split()[-2]

If you want to get only numbers:

>>> output = "CPU Utilization          : 5 %"
>>> [int(s) for s in output.split() if s.isdigit()]
[5]

>>> output = "CPU Utilization          : 5 % % 4.44 : 1 : 2"
>>> [int(s) for s in output.split() if s.isdigit()]
[5, 4.44, 1, 2]

EDIT:

for line in output:
    print line # this will print every single line in a loop, so you can make:
    print [int(s) for s in line.split() if s.isdigit()]
In [27]: mystring= "% 5 %;%,;;;;;%"
In [28]: ''.join(c for c in mystring if c.isdigit())
Out[28]: '5'

faster way :

def find_digit(mystring):
    return filter(str.isdigit, mystring)

find_digit(mystring)
5
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top