Python - 如何解析smartctl程序的输出?

5
我正在用Python 2.7.3编写一个smartctl的封装器(wrapper)......

我正在努力理解如何解析Linux(具体来说是Ubuntu x64)中smartctl程序的输出,这真是一场噩梦。

我通过子进程运行smartctl -l selftest /dev/sdx并将输出存入变量中。

然后将该变量分割成一个列表,再从输出中删除无用的标题数据和空白行。

现在,我得到了一个字符串列表,非常好!

数据有点类似于表格,我想将其解析为一个包含列表的字典(根据文档阅读,我认为这是在Python中表示表格数据的正确方式)。

以下是数据样例:

Num  Test_Description    Status                  Remaining  LifeTime(hours)  LBA_of_first_error
# 1  Short offline       Completed without error       00%     44796         -
# 2  Short offline       Completed without error       00%     44796         -
# 3  Short offline       Completed without error       00%     44796         -
# 4  Short offline       Completed without error       00%     44796         -
# 5  Short offline       Completed without error       00%     44796         -
# 6  Extended offline    Completed without error       00%     44771         -
# 7  Short offline       Completed without error       00%     44771         -
# 8  Short offline       Completed without error       00%     44741         -
# 9  Short offline       Completed without error       00%         1         -
#10  Short offline       Self-test routine in progress 70%     44813         -

我能看到尝试解析这个文本存在一些问题,我愿意听取解决方案,但我可能也做错了;
  1. 状态文本“正在进行自检例程”超过了文本“剩余”的第一个字符
  2. 在Num列中,9后面的数字与#字符之间没有空格分隔。
我可能完全错了,这是我第一次尝试解析如此古怪的东西。
提前感谢每一个读完这篇拙劣文章的人!!!
以下是迄今为止我的代码,如果有任何人认为或发现它有用的话:
#testStatus.py

#This module provides an interface for retrieving
#test status and results for ongoing and completed
#drive tests

import subprocess

#this function takes a list of strings and removes
#strings which do not have pertinent information
def cleanOutput(data):

  cleanedOutput = []

  del data[0:3] #This deletes records 0-3 (lines 1-4) from the list

  for item in data:
    if item == '': #This removes blank items from remaining list
      pass
    else:
      cleanedOutput.append(item)

  return cleanedOutput


def resultsOutput(data):

  headerLines = []
  resultsLines = []
  resultsTable = {}

  for line in data:
    if "START OF READ" in line or "log structure revision" in line:
      headerLines.append(line)
    else:
      resultsLines.append(line)

  nameLine = resultsLines[0].split()
  print nameLine


def getStatus(sdxPath):
  try:
    output = subprocess.check_output(["smartctl", "-l", "selftest", sdxPath])

  except subprocess.CalledProcessError:
    print ("smartctl command failed...")

  except Exception as e:
    print (e)

  splitOutput = output.split('\n')

  cleanedOutput = cleanOutput(splitOutput)

  resultsOutput(cleanedOutput)


#For Testing
getStatus("/dev/sdb")
2个回答

6

这是一个老问题,但smartctl自7.0版本起有了--json标志,您可以使用它来解析输出的普通JSON。

发行说明


@FlorianB 网络上的手册副本几乎总是过时的,Debian 有最新版的手册(当然,如果您安装它,则也可以获得最新版的手册)https://manpages.debian.org/unstable/smartmontools/smartctl.8.en.html:部分运行时行为选项。 - David Costa
嗯,看来我要使用的系统卡在6.6版本上,这真是太巧了。除了努力推动系统更新到更高版本的smartctl之外,我想没有其他解决方案了吧? - Michael

1

主要解析问题似乎集中在前三列,其余数据比较直接。假设输出使用字段之间的空格(而不是制表符,这样会更容易解析),我会选择固定长度解析,例如:

num = line[1:2]
desc = line[5:25]
status = line[25:54]
remain = line[54:58]
lifetime = line[60:68]
lba = line[77:99]

头部行将被处理得不同。你把数据放入什么结构中取决于你想要做什么。如果你主要想通过“num”标识符随机访问数据,那么以“num”为键的字典可能是合适的。否则,列表可能更好。每个条目(每行)可以是元组、列表、字典、类实例或其他东西。如果你想按名称访问字段,则每个条目的字典或类实例可能是合适的。


感谢您分享您智慧、美丽的思想!您是一位绅士和学者... - Pyrotherm

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接