【问题标题】:Parsing a command output - Python解析命令输出 - Python
【发布时间】:2017-01-09 05:13:34
【问题描述】:

我正在运行一个解析df 命令输出的实用程序。我捕获输出并将其发送到我的解析器。这是一个示例:

Filesystem                512-blocks      Used  Available Capacity iused      ifree %iused  Mounted on
/dev/disk2                1996082176 430874208 1564695968    22% 2429281 4292537998    0%   /
devfs                            668       668          0   100%    1156          0  100%   /dev
map -hosts                         0         0          0   100%       0          0  100%   /net
map auto_home                      0         0          0   100%       0          0  100%   /home

函数如下:

def parse_df(self, content):
    """Parse the `df` content output

    :param content: The command content output
    :return: (list) A list of objects of the type being parsed
    """
    entries = []
    if not content:
       return entries
    # Split the content by line and check if we should ignore first line
    for line in content.split("\n"):
        if line.startswith("Filesystem"):
            continue
        tokens = line.split()
        print tokens

但是我得到以下输出:

['/dev/disk2', '1996082176', '430876480', '1564693696', '22%', '2429288', '4292537991', '0%', '/']
['devfs', '668', '668', '0', '100%', '1156', '0', '100%', '/dev']
['map', '-hosts', '0', '0', '0', '100%', '0', '0', '100%', '/net']
['map', 'auto_home', '0', '0', '0', '100%', '0', '0', '100%', '/home']

问题是 map -host 应该是单个元素(对于 Filesystem 列)。 我尝试应用正则表达式tokens = re.split(r'\s{2,}', line),但结果仍然不正确:

['/dev/disk2', '1996082176 430869352 1564700824', '22% 2429289 4292537990', '0%', '/']

解析输出的正确方法是什么?

【问题讨论】:

  • 您需要使用不同的分隔符,比如\t?甚至多个空格也可以。
  • 每一列都有固定的宽度。您可以尝试基于此拆分
  • @Nishant:按\t拆分:['/dev/disk2 1996082176 430874728 1564695448 22% 2429300 4292537979 0% /']
  • 听起来像是正则表达式的工作;或os.statvfs.
  • 不相关,但有一些系统调用(例如 statvfs)可能会更直接地得到你想要的。

标签: python regex


【解决方案1】:

只拆分一个或多个空格,后跟一个数字或/

>>> import re
>>> s = '''/dev/disk2                1996082176 430874208 1564695968    22% 2429281 4292537998    0%   /
devfs                            668       668          0   100%    1156          0  100%   /dev
map -hosts                         0         0          0   100%       0          0  100%   /net
map auto_home                      0         0          0   100%       0          0  100%   /home'''.splitlines()
>>> for line in s:
    print re.split(r'\s+(?=[\d/])', line)


['/dev/disk2', '1996082176', '430874208', '1564695968', '22%', '2429281', '4292537998', '0%', '/']
['devfs', '668', '668', '0', '100%', '1156', '0', '100%', '/dev']
['map -hosts', '0', '0', '0', '100%', '0', '0', '100%', '/net']
['map auto_home', '0', '0', '0', '100%', '0', '0', '100%', '/home']
>>> 

【讨论】:

    【解决方案2】:

    如果这是你想要的行为,我能看到的最简单的方法是加入数组的第一个元素,直到你到达一个数字元素。

    所以是这样的:

    tokens = line.split()
    n = 1
    while n < len(tokens) and not tokens[n].isdigit():
        n += 1
    tokens[0] = ' '.join(tokens[:n])
    tokens = [ tokens[0] ] + tokens[n:]
    

    您也可以试试@cricket_007 的建议:

    first_token = line[:15].strip()
    tokens = [ first_token ] + [ x.strip() for x in line[15:].split() ]
    

    【讨论】:

      【解决方案3】:

      由于 FS 可能会有多个空格,只要您可以预先确定可以使用不同的分隔符进行拆分并最终将它们组合起来。

      fs, rest = re.split(r'\s{2,}', line, 1)
      result = [fs] + rest.split()
      

      但这行不通,fs 被一个空格隔开,就像一个大空格。

      同意 cmets 使用 os.statvfs(path) 是一个更好的工具。 df 将是一个 subprocess 电话。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-25
        • 2014-01-14
        • 1970-01-01
        • 2023-03-19
        • 1970-01-01
        相关资源
        最近更新 更多