2

Is there a way to sort a list in Ansible or Jinja in a natural way?

For example this is the list

test
test123
test12
test5
test1234test
test22te

And I need it to take in account the numbers as whole not as individual so test12 is under test5 and so on.

β.εηοιτ.βε
  • 33,893
  • 13
  • 69
  • 83
VladoPortos
  • 563
  • 5
  • 21

2 Answers2

2

Given the list

  l1:
    - test
    - test123
    - test12
    - test5
    - test1234test
    - test22te

Create a list with an attribute index of type integer, e.g.

    - set_fact:
        l2: "{{ l2|default([]) +
                [{'index': (_index|length > 0)|ternary(_index|int, 0),
                  'name': item}] }}"
      loop: "{{ l1 }}"
      vars:
        _regex: '^test(\d*)\D*$'
        _replace: '\1'
        _index: "{{ item|regex_replace(_regex, _replace) }}"
    - debug:
        msg: "{{ l2|sort(attribute='index')|
                    map(attribute='name')|
                    list }}"

gives

  msg:
  - test
  - test5
  - test12
  - test22te
  - test123
  - test1234test

Without iteration, declare the variables

  _regex: '^test(\d*)\D*$'
  _replace: '\1'
  _index: "{{ l1|map('regex_replace', _regex, _replace)|map('int')|list }}"
  l2: "{{ dict(_index|zip(l1))|
                      dict2items|
                      sort(attribute='key')|
                      map(attribute='value')|
                      list }}"

gives the same result

  l2:
  - test
  - test5
  - test12
  - test22te
  - test123
  - test1234test

Example of a complete playbook for testing

- hosts: localhost

  vars:

    l1:
      - test
      - test123
      - test12
      - test5
      - test1234test
      - test22te

    _regex: '^test(\d*)\D*$'
    _replace: '\1'
    _index: "{{ l1|map('regex_replace', _regex, _replace)|map('int')|list }}"
    l2: "{{ dict(_index|zip(l1))|
                        dict2items|
                        sort(attribute='key')|
                        map(attribute='value')|
                        list }}"

  tasks:

    - debug:
        var: _index
    - debug:
        var: l2
Vladimir Botka
  • 58,131
  • 4
  • 32
  • 63
0

In the end made jinja filter "natsort_filter.py" that does what I need. Get it here if you like:

https://gitlab.privatecloud.sk/vladoportos/custom-jinja-filters

It does require natsort module for python, but than it works just fine :)

VladoPortos
  • 563
  • 5
  • 21
  • Hello I tried to follow, https://gitlab.privatecloud.sk/vladoportos/custom-jinja-filters created filter_plugins inside role directory and install pip install natsort but noluck it gives error. ~~~ msg": "template error while templating string: no filter named 'natsort' ~~~ – omankame Apr 09 '22 at 04:28
  • @omankame check where you run the block, if its in localhost (delegate localhost) or on the target host... try to manually import natsort in python cmd to see if its really there – VladoPortos Apr 10 '22 at 12:05
  • Ok Will try this. – omankame Apr 11 '22 at 16:49