Bootstrap FreeKB - Ansible - Loop through JSON
Ansible - Loop through JSON

Updated:   |  Ansible articles

When using the register parameter, the output is almost always returned as JSON. Here is an example of using the register parameter with the find module. The debug module can be used to print the JSON.

---
- hosts: localhost
  tasks:
  - find:
      paths: /tmp
    register: out

  - debug:
      var: out
...

 

Which should return JSON like this.

ok: [localhost] => {
    "out": {
        "changed": false,
        "examined": 1,
        "failed": false,
        "files": [],
        "matched": 0,
        "msg": ""
    }
}

 

Let's say you only want to print the "matched" key.

---
- hosts: localhost
  tasks:
  - find:
      paths: /tmp
    register: out

  - debug:
      var: out.matched
...

 

Which should return something like this.

ok: [server1.example.com] => {
    out.matched: 0
}

 


Let's say the following JSON is returned. Notice here that the "files" key is a list, as indicated by the [ ] brackets.

ok: [server1.example.com] => {
    "out": {
        "files": [
            {
              "path": "/tmp/foo.txt",
           }
            {
              "path": "/tmp/bar.txt",
           }
        ],
    }
}

 

One option is to do something like this. Index 0 is used to enter the first "files" key. If there were another "files" key, then index 1 would be used for the following files key.

- debug:
    msg: "{{ out.files[0].path}}"

 

Or you could loop over the files array.

- debug:
    msg: "{{ item.path }}"
  with_items: "{{ out.files }}"

 

Which should return something like this.

ok: [server1.example.com] => {
    "msg": "/tmp/foo.txt"
}

ok: [server1.example.com] => {
    "msg": "/tmp/bar.txt"
}

 

Or like this.

- debug:
    msg: "{{ items }}"
  vars:
    items: "{{ out.files | map(attribute='path') | list }}"

 

Which should return something like this.

ok: [server1.example.com] => {
    "msg": [
        "/tmp/foo.txt",
        "/tmp/bar.txt"
    ]
}

 


loop / with_items

Let's say you are using the loop or with_items parameter.

- find:
    paths: /tmp
  with_items: [ foo, bar ]
  register: out

 

In this scenario, the JSON that is returned will begin with the "results" array and the "item" key.

ok: [server1.example.com] => {
    "out": {
        "results": [
            "item": "foo",
            "files": [
                {
                  "path": "/tmp/foo.txt",
               }
                {
                  "path": "/tmp/bar.txt",
               }
            ],
            "item": "bar",
            "files": [
                {
                  "path": "/tmp/foo.txt",
               }
                {
                  "path": "/tmp/bar.txt",
               }
            ]
        ]
    }
}

 


index_of

Or, the index_of module can be used to get the index number of an element in a list/array, to avoid looping through each element in the array, which can be useful in reducing the amount of output returned when looping through a large list.

---
- hosts: localhost
  gather_facts: false
  vars:
    fruit:
     - apple
     - banana
     - orange
     - grapes
  tasks:
  - debug:
      msg: "banana index number = {{ lookup('ansible.utils.index_of', fruit, 'regex', 'banana') }}"
...

 

Running this playbook should return the following.

ok: [localhost] => {
    "msg": "banana index number = 1"
}

 




Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


January 23 2022 by Pavel
Thank you very much. I've read tons of posts and docs trying to iterate through uri module results, but your article was the one that showed the correct and simple (!) way.

Add a Comment


Please enter 1e6bbd in the box below so that we can be sure you are a human.