Tom
Tom

Reputation: 7

Parsing output in ansible using jinja2 template (mapping list of strings to list of strings)

Let's consider following output of some command (it is debug of stdout_lines):

- command: "some command"
  register: output
- debug: 
    msg: "{{ output.stdout_lines }}"


"msg": [
    "X", 
    "Y", 
    "Z", 
    "   1 some_word1", 
    "   1 some_word2", 
    "   1 some_word3", 
    "   1 some_word4"
]

The output is registered in variable output using command task. Now, I need to parse it into a list of the form: [some_word1,some_word2,some_word3,some_word4].
Please keep in mind that output can contain more or less (even 0) than 4 words.

When it comes to "X","Y","Z" they are constant (always three lines) so I can skip it using:

- debug:
    msg: "{{ output.stdout_lines[3:] }}"

However, I don't know how to deal with leading spaces and digit.
Could you give me some clues, please?

Upvotes: 1

Views: 2104

Answers (1)

β.εηοιτ.βε
β.εηοιτ.βε

Reputation: 39119

Knowing a string is "just" a list of char in python, if your output is always

/[[:space:]]+[[:digit:]] (.*)/

and never

/[[:space:]]+[[:digit:]]+ (.*)/

e.g. 1 some_word1 or 9 some_word9 but not 10 some_word10

Then you could apply the trim filter and just reuse your same list index trick, ending with this jinja expression:

---
- hosts: local
  vars:
    "msg": [
        "X",
        "Y",
        "Z",
        "   1 some_word1",
        "   1 some_word2",
        "   1 some_word3",
        "   1 some_word4"
    ]

  tasks:
    - debug:
        msg: "{{ (item | trim())[2:] }}" # after trimming the item, we just ignore the first two char as you did for your three first output lines
      with_items: "{{ msg[3:] }}"

This outputs:

/data/playbooks # ansible-playbook so.yml

PLAY [local] *******************************************************************

TASK [Gathering Facts] *********************************************************
ok: [host1]

TASK [debug] *******************************************************************
ok: [host1] => (item=   1 some_word1) => {
    "msg": "some_word1"
}
ok: [host1] => (item=   1 some_word2) => {
    "msg": "some_word2"
}
ok: [host1] => (item=   1 some_word3) => {
    "msg": "some_word3"
}
ok: [host1] => (item=   1 some_word4) => {
    "msg": "some_word4"
}

PLAY RECAP *********************************************************************
host1                      : ok=2    changed=0    unreachable=0    failed=0  

Now if you have the second form, or if you want to make it more the bash way, then you could change your command to a shellbecause shell accepts piping when command does not – and pipe your output to awk:

---
- hosts: local

  tasks:
    - shell: printf "X\nY\nZ\n   1 some_word1\n   1 some_word2\n   1 some_word3\n   1 some_word4" |  awk '{print $2}'
      register: output
    - debug:
        msg: "{{ output.stdout_lines[3:] }}"

This outputs:

/data/playbooks # ansible-playbook so.yml

PLAY [local] *******************************************************************

TASK [Gathering Facts] *********************************************************
ok: [host1]

TASK [shell] *******************************************************************
changed: [host1]

TASK [debug] *******************************************************************
ok: [host1] => {
    "msg": [
        "some_word1",
        "some_word2",
        "some_word3",
        "some_word4"
    ]
}

PLAY RECAP *********************************************************************
host1                      : ok=3    changed=1    unreachable=0    failed=0 

Upvotes: 1

Related Questions