【问题标题】:How can I read one line from a telnet response with Python?如何使用 Python 从 telnet 响应中读取一行?
【发布时间】:2013-04-21 01:22:39
【问题描述】:

我很惊讶我在这里找不到这个问题。

我想从 telnet 响应中提取一行并将其设为变量。 (实际上是该行的一个数字)。我可以使用 telnet.read_until() 提取到我需要的地方,但整个开头仍然存在。打印输出显示机器的不同状态。

我试图获取的行格式如下:

CPU Utilization          : 5 %

我真的只需要数字,但在输出的其余部分中有很多 ':' 和 '%' 字符。谁能帮我提取这个值?提前致谢!

这是我的代码(读取整个输出并打印):

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")

编辑:输出的一些示例:

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

【问题讨论】:

  • 你说:%有很多,请给我们展示更多的示例输出行,以便我们给你更好的答案
  • @Johnny 添加和编辑行

标签: python python-3.x telnet python-3.3 telnetlib


【解决方案1】:

正如你在问题中所说:

我可以使用telnet.read_until() 提取到我需要的位置,但整个开头仍然存在。

因此,您可以将所有行添加到变量output 中,包括您想要的行。您唯一缺少的是如何获取 output 字符串中的最后一行,对吧?

这很简单:只需将output 分成几行并取最后一行:

output.splitlines()[:-1]

或者干脆把最后一行分开:

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

这不会改变输出,它只是一个计算新值的表达式(output 中的最后一行)。所以,只是这样做,然后是print(output),不会做任何明显有用的事情。

让我们举一个更简单的例子:

a = 3
a + 1
print(a)

这显然会打印3。如果你想打印4,你需要这样的东西:

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

所以,回到真实的例子,你想要的可能是这样的:

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

现在你会看到这个:

CPU Utilization          : 5 %

当然,您仍然需要类似 Johnny 的代码来从该行的其余部分提取数字:

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

现在你会得到这个:

['5']

注意,它会为您提供一个字符串的列表。如果你只想要一个字符串,你还有另一个步骤:

number = numbers[0]
print(number)

这给了你:

5

最后,number 仍然是 字符串 '5',而不是整数 5。如果需要,请将最后一位替换为:

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

这仍然会打印出5,但现在你有了一个可以实际用作数字的变量:

print(number / 100.0) # convert percent to decimal

我依赖于 telnet defines end-of-line as \r\n 和任何不完全兼容 telnet 的服务器出错几乎肯定会使用 Windows 样式(也有 \r\n)或 Unix 样式(只是\n) 行尾。因此,在\n 上拆分总是会得到最后一行,即使是对于糟糕的服务器也是如此。如果您不需要担心额外的健壮性,您可以拆分 \r\n 而不是 \n


还有其他方法可以解决这个问题。我可能会使用session.expect([r'CPU Utilization\s*: (\d+)\s*%']) 之类的东西,或者将会话包装为行的迭代器(如文件),然后编写标准的itertools 解决方案。但考虑到你已经拥有的东西,这似乎是最简单的。

【讨论】:

  • @mad5245:是的,但是您已经知道如何使用read_until 使所有行都达到并包括您想要的行,对吧?因此,要获取这些行的最后一行(这是您想要的行),只需执行 read_until,然后如上所示取最后一行。
  • “不适合我”是什么意思?如果您只是计算output.rpartition(b'\r\n')[-1] 而没有存储或打印或以其他方式使用结果,那么它不会很有用......
  • 对于任何列表(或其他序列)foofoo[-1] 是最后一个元素。 rpartition(b'\r\n') 函数返回直到最后一个 b'\r\n' 的所有内容,然后是 b'\r\n' 本身,然后是它之后的所有内容。因此,将它们放在一起,就可以得到一切。您确定您实际上有 b'\r\n' 而不是 b'\n' 或其他以您的字符串结尾的行吗? (您是否尝试过记录其repr 以确保?)
  • 同时,“它不只占用最后一行”是什么意思?这里的“它”是什么?同样,您必须使用表达式的结果。如果这是您所期望的,它不会就地更改 output 或任何其他变量。
  • 再一次,仅在output 上调用partition 不会更改output 或任何其他就地变量。它返回一个新值。如果您想以任何方式使用它,您必须将该新值存储在另一个变量中,或者将其打印出来,或者其他任何方式。我不确定如何更简单地解释这一点,但我会尝试编辑一些示例代码来回答,看看它是否有帮助。
【解决方案2】:

据我了解,您想从一行行中选择 1 行,但不一定是最后一行。

您感兴趣的行总是以“CPU Utilization”开头

这应该可行:

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

【讨论】:

  • 根据提问,他的read_until总是以“CPU Utilization”这一行结尾,所以没必要这么做。
  • 另外,你为什么要显式调用line.__contains__(foo) 而不是只使用foo in line
  • @abarnert 实际上,OP 声明,“我实际上想要在输出中间有一条线。它不在静态位置”
  • 所以这个方法给了我和 abarnert 的方法一样的效果。它为我提供了所有数据,包括我需要的行。有没有我需要的导入?
  • 此方法将逐行查找包含字符串“CPU Utilization”的一行。一旦找到该行,它就会将该行拆分为使用空格作为分隔符的块。然后它从最后一个块中取出第二个,这是您感兴趣的数字部分,并将其存储在变量 cpu_utilization 中。
【解决方案3】:

如果你只想得到数字:

>>> 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]

编辑:

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()]

【讨论】:

  • 我认为这是我需要的,但我怎样才能让输出只是那一行? “CPU Utilization : 5 %”前后都有设置。谢谢
  • 只是循环输出(见我的编辑)
  • 循环输出没有帮助。他只想获取 CPU 利用率数字,而不是每个数字。
【解决方案4】:
In [27]: mystring= "% 5 %;%,;;;;;%"
In [28]: ''.join(c for c in mystring if c.isdigit())
Out[28]: '5'

更快的方式:

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

find_digit(mystring)
5

【讨论】:

  • 这似乎是一个非常糟糕的主意。如果你给它"CPU Utilization : 5 % % 4.44 : 1 : 2",你会得到数字544412。没有理由将它逐个字符分解,然后重新加入word;鉴于他的号码显然是用空格分隔的,你可以一开始就逐字逐句。
  • 好吧,我认为这是问题中写的唯一数字:but there are many ':' and '%' characters in the rest of the output
  • 阅读他的 cmets 其他答案。例如,“在……之前和之后还有其他设置”,并且大概这些设置行有数字以及冒号和百分比。
  • 他在我提交代码后发布了这些内容。他可能应该把这些信息放在原来的问题中
  • 同意,他应该。但是,一个对 OP(或任何人)的实际问题没有用的答案并不会变得有用,因为它在技术上是正确的,因为 OP 没有正确说明他的问题。
猜你喜欢
  • 2015-03-26
  • 1970-01-01
  • 2016-06-01
  • 2018-07-10
  • 2021-04-22
  • 1970-01-01
  • 1970-01-01
  • 2011-10-30
  • 2015-02-27
相关资源
最近更新 更多