Chand
Chand

Reputation: 320

How to search and match pattern to get a value in ansible

My variable info has below value. (Actual case has huge data).

I am trying to search for specific word XYZ_data_001 and get the size information, which is after the pattern physical disk,

XYZ_data_001         file system device, special, dsync off, directio on, physical disk, 16384.00 MB, Free: 0.00 MB      2         0      6       0  8388607
XYZ_data_002         file system device, special, dsync off, directio on, physical disk, 16384.00 MB, Free: 0.00 MB      2         0     13       0  8388607

here is what is tried

    - name: Print size
      ansible.builtin.debug:
        msg: "{{ info | regex_search('XYZ_data_001(.+)') | split('physical disk,') | last }}"

this will give me below output

ok: [testhost] => {
    "msg": " 16384.00 MB, Free: 0.00 MB      2         0      6       0  8388607 "
}

Thanks in advance

Upvotes: 2

Views: 289

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 68104

There are two filters in the collection Community.General that will help you to create dictionaries from the info.

  1. Split the lines, split and trim the items, and use the filter community.general.dict to create the list of dictionaries
  info_dict1: "{{ info.splitlines()|
                  map('split', ',')|
                  map('map', 'trim')|
                  map('zip', ['dev', 'spec', 'dsync', 'dir', 'disk', 'size', 'free'])|
                  map('map', 'reverse')|
                  map('community.general.dict') }}"

gives

  info_dict1:
  - dev: XYZ_data_001         file system device
    dir: directio on
    disk: physical disk
    dsync: dsync off
    free: 'Free: 0.00 MB      2         0      6       0  8388607'
    size: 16384.00 MB
    spec: special
  - dev: XYZ_data_002         file system device
    dir: directio on
    disk: physical disk
    dsync: dsync off
    free: 'Free: 0.00 MB      2         0     13       0  8388607'
    size: 16384.00 MB
    spec: special
  1. Split the attribute dev and use the filter community.general.dict_kv to create the list of dictionaries with the attribute device
  info_dev: "{{ info_dict1|
                map(attribute='dev')|
                map('split')|
                map('first')|
                map('community.general.dict_kv', 'device') }}"

gives

  info_dev:
  - device: XYZ_data_001
  - device: XYZ_data_002

Combine the dictionaries

  info_dict2: "{{ info_dict1|zip(info_dev)|map('combine') }}"

gives

  info_dict2:
  - dev: XYZ_data_001         file system device
    device: XYZ_data_001
    dir: directio on
    disk: physical disk
    dsync: dsync off
    free: 'Free: 0.00 MB      2         0      6       0  8388607'
    size: 16384.00 MB
    spec: special
  - dev: XYZ_data_002         file system device
    device: XYZ_data_002
    dir: directio on
    disk: physical disk
    dsync: dsync off
    free: 'Free: 0.00 MB      2         0     13       0  8388607'
    size: 16384.00 MB
    spec: special

This way you can add other attributes if needed.


Q: "Search for specific word XYZ_data_001 and get the size."

A: Create a dictionary device_size

  device_size: "{{ info_dict2|items2dict(key_name='device', value_name='size') }}"

gives

  device_size:
    XYZ_data_001: 16384.00 MB
    XYZ_data_002: 16384.00 MB

Search the dictionary

    - debug:
        msg: "Size of XYZ_data_001 is {{ device_size.XYZ_data_001 }}"

gives

  msg: Size of XYZ_data_001 is 16384.00 MB

Example of a complete playbook for testing

- hosts: localhost

  vars:

    info: |
      XYZ_data_001         file system device, special, dsync off, directio on, physical disk, 16384.00 MB, Free: 0.00 MB      2         0      6       0  8388607
      XYZ_data_002         file system device, special, dsync off, directio on, physical disk, 16384.00 MB, Free: 0.00 MB      2         0     13       0  8388607

    info_dict1: "{{ info.splitlines()|
                    map('split', ',')|
                    map('map', 'trim')|
                    map('zip', ['dev', 'spec', 'dsync', 'dir', 'disk', 'size', 'free'])|
                    map('map', 'reverse')|
                    map('community.general.dict') }}"

    info_dev: "{{ info_dict1|
                  map(attribute='dev')|
                  map('split')|
                  map('first')|
                  map('community.general.dict_kv', 'device') }}"

    info_dict2: "{{ info_dict1|zip(info_dev)|map('combine') }}"

    device_size: "{{ info_dict2|items2dict(key_name='device', value_name='size') }}"

  tasks:

    - debug:
        var: info_dict1
    - debug:
        var: info_dev
    - debug:
        var: info_dict2
    - debug:
        var: device_size
    - debug:
        msg: "Size of XYZ_data_001 is {{ device_size.XYZ_data_001 }}"

Upvotes: 1

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 627044

You can use

{{ info | regex_search('XYZ_data_001\\b.*physical disk,\\s*(\\d[\\d.]*)', '\\1') }}

See the regex demo.

Details:

  • XYZ_data_001 - a XYZ_data_001 string
  • \b - a word boundary
  • .* - any text (any zero or more chars other than line break chars as many as possible)
  • physical disk, - a literal string
  • \s* - zero or more whitespaces
  • (\d[\d.]*) - Group 1 (\1): a digit and then zero or more digits or dots.

Upvotes: 2

Related Questions