如何从 Ansible 中以 table 分隔的宽度中提取值?

How do I extract values from a width delimited table in Ansible?

我正在尝试从打印到标准输出的 SQL 命令的结果中提取值。

  first      second
  29494060   23004496
  29774383   22979864

我想把它解析成这样的数据结构

[
  { first: 29494060, second: 23004496 },
  { first: 29774383, second: 22979864 }
]

这样我就可以访问每条记录的值,例如 {{ item.first }}{{ item.second }}

我已经能够通过使用 regex_replace 过滤器提取的值创建对象文字来提取单个记录。

- set_fact:
    items: { first: "{{ item | regex_replace('\s*?(\d+)\s*?(\d+)', '\1') }}", second: "{{ item | regex_replace('\s*?(\d+)\s*?(\d+)', '\2') }}" }
  loop: '{{ command_out.stdout_lines }}'

这只保留最后一行的结果。我无法为每个结果创建一个列表。由于嵌套的 Jinja 模板,我无法使用像 items: "{{ items | default([]) + [{…}] }}" 这样的列表连接。

如何将打印的 table 数据提取到对象列表中?

创建。例如

- set_fact:
    keys: "{{ command_out.stdout_lines[0].split() }}"
- debug:
    var: keys

给予

"keys": [
    "first", 
    "second"
]

然后将过滤器 dict and zip 创建的词典添加到列表 sql_list

- set_fact:
    sql_list: "{{ sql_list|default([]) +
                  [dict(keys|zip(item.split()))] }}"
  loop: "{{ command_out.stdout_lines[1:] }}"
- debug:
    var: sql_list

给予

"sql_list": [
    {
        "first": "29494060", 
        "second": "23004496"
    }, 
    {
        "first": "29774383", 
        "second": "22979864"
    }
]

custom plugins 简化的任务给出相同的结果

- set_fact:
    sql_list: "{{ command_out.stdout_lines[1:]|
                  map('string_split')|
                  map('list_dict_zip_rev', keys)|
                  list }}"
$ cat filter_plugins/string_filters.py
def string_split(s, *i):
    if len(i) == 0:
        return s.split()
    elif len(i) == 1:
        return s.split(i[0])
    else:
        return s.split(i[0], i[1])

def list_dict_zip_rev(l,k):
    return dict((y,x) for x,y in  zip(l,k))

class FilterModule(object):
    ''' Ansible filters.'''

    def filters(self):
        return {
            'list_dict_zip_rev' : list_dict_zip_rev,
            'string_split' : string_split
        }