![](/base_images/jeremy.jpg)
The following parameters can be used to loop through each item in a list.
- loop
- vars
- with_items
- with_indexed_items
- with_list
- with_nested (this article)
- with_sequence
The with_nested parameter can be used to loop over two unique lists.
---
- hosts: all
tasks:
- ansible.builtin.debug:
msg: "{{ item[0] }} and {{ item[1] }}"
with_nested:
- [ 'apple', 'banana' ]
- [ 'onion', 'pepper' ]
...
In this example, the following should be returned.
TASK [debug]
ok: [server1.example.com] => (item=['apple', 'onion']) => {
"msg": "apple and onion"
}
ok: [server1.example.com] => (item=['apple', 'pepper']) => {
"msg": "apple and pepper"
}
ok: [server1.example.com] => (item=['banana', 'onion']) => {
"msg": "banana and onion"
}
ok: [server1.example.com] => (item=['banana', 'pepper']) => {
"msg": "banana and pepper"
}
Here is a bit of a more practical example.
---
- hosts: all
tasks:
- name: append foo and bar to file1.txt and file2.txt
ansible.builtin.lineinfile:
path: "{{ item[0] }}"
line: "{{ item[1] }}"
with_nested:
- [ 'file1.txt', 'file2.txt' ]
- [ 'foo', 'bar' ]
...
It is important to recognize that with_nested is probably not going to do what you think it would do if you have a dictionary that contains a nested list. Take for example the following.
---
- hosts: all
vars:
outer:
- inner:
- { foo: hello }
- { foo: world }
tasks:
- ansible.builtin.debug:
var: out
...
Running this playbook should return the following. Notice there are two lists, "outer" and "inner".
ok: [server1.example.com] => {
"outer": [
{
"inner": [
{
"foo": "hello"
},
{
"foo": "world"
}
]
}
]
}
Looping over the "outer" list is totally straight forward.
---
- hosts: all
vars:
outer:
- inner:
- { foo: hello }
- { foo: world }
tasks:
- ansible.builtin.debug:
msg: "{{ item }}"
with_items: "{{ outer }}"
...
Which should return something like this.
ok: [server1.example.com] => (item={'inner': ['hello', 'world']}) => {
"msg": {
"inner": [
{
"foo": "hello"
},
{
"foo": "world"
}
]
}
}
Then to just return the key/value pairs in the "inner" list.
---
- hosts: all
vars:
outer:
- inner:
- { foo: hello }
- { foo: world }
tasks:
- ansible.builtin.debug:
msg: "{{ item.inner }}"
with_items: "{{ outer }}"
...
Should return something like this.
ok: [server1.example.com] => (item={'inner': [{'foo': 'hello'}, {'foo': 'world'}]}) => {
"msg": [
{
"foo": "hello"
},
{
"foo": "world"
}
]
}
But to return a specific item in the "inner" list you'd have to include the index number.
---
- hosts: all
vars:
outer:
- inner:
- { foo: hello }
- { foo: world }
tasks:
- ansible.builtin.debug:
msg: "{{ item.inner[0] }}"
with_items: "{{ outer }}"
...
Which returns foo: hello but does not return foo: world.
ok: [server1.example.com] => (item={'inner': [{'foo': 'hello'}, {'foo': 'world'}]}) => {
"msg": {
"foo": "hello"
}
}
Or, to just return the value of the "foo" key in index 0.
---
- hosts: all
vars:
outer:
- inner:
- { foo: hello }
- { foo: world }
tasks:
- ansible.builtin.debug:
msg: "{{ item.inner[0].foo }}"
with_items: "{{ outer }}"
...
Returns "hello" but does not return "world".
ok: [server1.example.com] => (item={'inner': [{'foo': 'hello'}, {'foo': 'world'}]}) => {
"msg": "hello"
}
But what if you have dynamic data and you can't predict the index number? In this situation, what I typically do is store the "inner" list in its own list.
---
- hosts: all
vars:
outer:
- inner:
- { foo: hello }
- { foo: world }
tasks:
- ansible.builtin.set_fact:
inner: "{{ item.inner }}"
with_items: "{{ outer }}"
- ansible.builtin.debug:
msg: "{{ item }}"
with_items: "{{ inner }}"
...
Which lets me loop through the items in the "inner" list without having to include index number. Nice!
ok: [server1.example.com] => (item={'foo': 'hello'}) => {
"msg": {
"foo": "hello"
}
}
ok: [server1.example.com] => (item={'foo': 'world'}) => {
"msg": {
"foo": "world"
}
}
Did you find this article helpful?
If so, consider buying me a coffee over at