When you're working with Ansible, it's inevitable that you'll deal with lists and dictionaries. After all, they are all part of YAML, which administrators use to create Ansible playbooks. In addition, Ansible uses lists and dictionaries to exchange data within processes and with third parties.
This article covers analyzing and using the data in lists and dictionaries, which is crucial for anything you want to do with Ansible.
[ Get started with IT automation with the Ansible Automation Platform beginner's guide. ]
What are lists?
Lists are the equivalent of an array, something used in many real programming languages (which Ansible is not).
The term "list" is self-explanatory, but here are some ways to represent lists:
vars:
bands:
- The Beatles
- Led Zeppelin
- The Police
- Rush
bands2: ['The Beatles', 'Led Zeppelin', 'The Police', 'Rush']
The values bands and bands2 are equivalent.
Lists are indexed by numbers (starting with zero). So if I want to use the first entry, bands, I use bands[0]. The second element is bands[1] and so forth. Later on, I will discuss methods to inspect, compare, and loop through lists.
[ Learn how to automate everything with Ansible Automation Platform. ]
What are dictionaries?
Dictionaries are the equivalent of hashes. They differ from a list because they are keyed using a string, not a number.
Here is one way to define a simple dictionary:
vars:
rockers:
drums: John Bonham
bass: John Paul Jones
guitar: Jimmy Page
vocals: Robert Plant
If I want to point to a specific entry, I can use the bracket notation rockers['drums'] to get the "John Bonham" string.
In some places, you may find dot notation, like rockers.drums, but this is not recommended. According to the Ansible documentation, "dot notation can cause problems because some keys collide with attributes and methods of Python dictionaries."
Work with lists
The following playbook contains two predefined hardcoded lists.
In more realistic scenarios, lists would come either from group_vars or from calls to Ansible modules.
---
- name: Lists
hosts: localhost
gather_facts: no
vars:
bands:
- The Beatles
- Led Zeppelin
- The Police
- Rush
bands2: ['The Beatles', 'Led Zeppelin', 'The Police', 'Rush']
tasks:
- name: T01 - List bands 1
ansible.builtin.debug:
msg: "{{ bands }}"
- name: T02 - List bands 2
ansible.builtin.debug:
msg: "{{ bands2 }}"
- name: T03 - Print specific element
ansible.builtin.debug:
msg: "{{ bands[0] }}"
- name: T04 - Process list using a loop
ansible.builtin.debug:
msg: "{{ item }}"
loop: "{{ bands }}"
- name: T05 - Add item to bands2
ansible.builtin.set_fact:
bands2: "{{ bands2 + ['Rolling Stones'] }}"
- name: T06 - Difference between bands2 and bands
ansible.builtin.debug:
msg: "{{ bands2 | difference(bands) }}"
- name: T07 - Show the data type of a list
ansible.builtin.debug:
msg: "{{ bands | type_debug }}"
...
This is the result of running this playbook:
PLAY [Lists] ******************************************************************
TASK [T01 - List bands 1] *****************************************************
ok: [localhost] => {
"msg": [
"The Beatles",
"Led Zeppelin",
"The Police",
"Rush"
]
}
TASK [T02 - List bands 2] *****************************************************
ok: [localhost] => {
"msg": [
"The Beatles",
"Led Zeppelin",
"The Police",
"Rush"
]
}
TASK [T03 - Print specific element] *******************************************
ok: [localhost] => {
"msg": "The Beatles"
}
TASK [T04 - Process list using a loop] ****************************************
ok: [localhost] => (item=The Beatles) => {
"msg": "The Beatles"
}
ok: [localhost] => (item=Led Zeppelin) => {
"msg": "Led Zeppelin"
}
ok: [localhost] => (item=The Police) => {
"msg": "The Police"
}
ok: [localhost] => (item=Rush) => {
"msg": "Rush"
}
TASK [T05 - Add item to bands2] ***********************************************
ok: [localhost]
TASK [T06 - Difference between bands2 and bands] ******************************
ok: [localhost] => {
"msg": [
"Rolling Stones"
]
}
TASK [T07 - Show the data type of a list] *************************************
ok: [localhost] => {
"msg": "list"
}
PLAY RECAP ********************************************************************
localhost : ok=7 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
In the output above:
- T01 - List bands 1 — Notice that the list is delimited by [ and ], and elements are separated by , .
- T02 - List bands 2 — It's the same for the second list (just to show they have the same content).
- T03 - Print-specific element — This uses the number zero as the index.
- T04 - Process list using a loop — Notice that each item is one element of the list.
- T05 - Add item to bands2
- T06 - Difference between bands2 and bands — This uses the filter difference to compare the lists.
- T07 - Show the data type of a list — You can inspect the output visually, as mentioned in task T01. However, in some situations, it may be useful to validate that a variable contains the type of data you expect and even use that information to handle the data.
[ Want to test your sysadmin skills? Take a skills assessment today. ]
Work with dictionaries
Above, I demonstrated a simple dictionary.
In real life, lists and dictionaries commonly appear combined, so here's a data structure that's a little more elaborate:
---
- name: Dictionaries
hosts: localhost
gather_facts: no
vars:
bands:
- name: The Beatles
drums: Ringo Star
bass: Paul McCartney
guitar:
- George Harrison
- John Lennon
vocals:
- John Lennon
- Paul McCartney
- George Harrison
- Ringo Star
- name: The Police
drums: Stewart Copeland
bass: Sting
guitar: Andy Summers
vocals: Sting
- name: Rush
drums: Neil Peart
bass: Geddy Lee
guitar: Alex Lifeson
vocals: Geddy Lee
- name: Led Zeppelin
drums: John Bonham
bass: John Paul Jones
guitar: Jimmy Page
vocals: Robert Plant
tasks:
- name: T01 - List bands
ansible.builtin.debug:
msg: "{{ bands }}"
- name: T02 - Select element based on band name
ansible.builtin.debug:
msg: "{{ bands | selectattr('name','equalto','The Beatles') }}"
- name: T03 - Show data types
ansible.builtin.debug:
msg:
- "bands............. is of type {{ bands | type_debug }}"
- ""
- "bands[0].......... is of type {{ bands[0] | type_debug }}"
- " name ====> {{ bands[0]['name'] }}"
- ""
- "bands[0]['guitar'] is of type {{ bands[0]['guitar'] | type_debug }}"
- " guitar ==> {{ bands[0]['guitar'] }}"
- ""
- "bands[1]['guitar'] is of type {{ bands[1]['guitar'] | type_debug }}"
- " guitar ==> {{ bands[1]['guitar'] }}"
...
Here is the result of running this playbook:
PLAY [Dictionaries] ************************************************************
TASK [T01 - List bands] ********************************************************
ok: [localhost] => {
"msg": [
{
"bass": "Paul McCartney",
"drums": "Ringo Star",
"guitar": [
"George Harrison",
"John Lennon"
],
"name": "The Beatles",
"vocals": [
"John Lennon",
"Paul McCartney",
"George Harrison",
"Ringo Star"
]
},
{
"bass": "Sting",
"drums": "Stewart Copeland",
"guitar": "Andy Summers",
"name": "The Police",
"vocals": "Sting"
},
{
"bass": "Geddy Lee",
"drums": "Neil Peart",
"guitar": "Alex Lifeson",
"name": "Rush",
"vocals": "Geddy Lee"
},
{
"bass": "John Paul Jones",
"drums": "John Bonham",
"guitar": "Jimmy Page",
"name": "Led Zeppelin",
"vocals": "Robert Plant"
}
]
}
TASK [T02 - Select element based on band name] *********************************
ok: [localhost] => {
"msg": [
{
"bass": "Paul McCartney",
"drums": "Ringo Star",
"guitar": [
"George Harrison",
"John Lennon"
],
"name": "The Beatles",
"vocals": [
"John Lennon",
"Paul McCartney",
"George Harrison",
"Ringo Star"
]
}
]
}
TASK [T03 - Show data types] ***************************************************
ok: [localhost] => {
"msg": [
"bands............. is of type list",
"",
"bands[0].......... is of type dict",
" name ====> The Beatles",
"",
"bands[0]['guitar'] is of type list",
" guitar ==> ['George Harrison', 'John Lennon']",
"",
"bands[1]['guitar'] is of type AnsibleUnicode",
" guitar ==> Andy Summers"
]
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Analysis of the above output:
- T01 - List bands — The highest level of this data structure is a list, which is indicated by the opening [ after "msg:" and closed by a matching ] two lines after "Robert Plant". Then at the second level, each member of this list is now a dictionary, delimited by { and }. This means each of the "bands" in the list is a dictionary.
- T02 - Select an element based on band name — From all the elements in the list, select only the dictionary where name='The Beatles'.
- T03 - Show data types — This is a sample of some of the elements and their data types.
In the data structure that I used here, some of the bands may have guitar or vocals as a single element ("AnsibleUnicode" in the output) or a list. If this were a real-life scenario, I would need to handle the situation accordingly.
I could also define the first level as a dictionary, like this:
---
- name: Dictionaries
hosts: localhost
gather_facts: no
vars:
bands:
The Beatles:
drums: Ringo Star
bass: Paul McCartney
guitar:
- George Harrison
- John Lennon
vocals:
- John Lennon
- Paul McCartney
- George Harrison
- Ringo Star
The Police:
drums: Stewart Copeland
bass: Sting
guitar: Andy Summers
vocals: Sting
Rush:
drums: Neil Peart
bass: Geddy Lee
guitar: Alex Lifeson
vocals: Geddy Lee
Led Zeppelin:
drums: John Bonham
bass: John Paul Jones
guitar: Jimmy Page
vocals: Robert Plant
tasks:
- name: T01 - List bands
ansible.builtin.debug:
msg: "{{ bands }}"
- name: T02 - Select element based on band name
ansible.builtin.debug:
msg: "{{ bands['The Beatles'] }}"
- name: T03 - Show keys of highest level dictionary
ansible.builtin.debug:
msg: "{{ bands.keys() }}"
...
In this case, printing the full variable would result in the following:
TASK [T01 - List bands] ********************************************************
ok: [localhost] => {
"msg": {
"Led Zeppelin": {
"bass": "John Paul Jones",
"drums": "John Bonham",
"guitar": "Jimmy Page",
"vocals": "Robert Plant"
},
"Rush": {
"bass": "Geddy Lee",
"drums": "Neil Peart",
"guitar": "Alex Lifeson",
"vocals": "Geddy Lee"
},
"The Beatles": {
"bass": "Paul McCartney",
"drums": "Ringo Star",
"guitar": [
"George Harrison",
"John Lennon"
],
"vocals": [
"John Lennon",
"Paul McCartney",
"George Harrison",
"Ringo Star"
]
},
"The Police": {
"bass": "Sting",
"drums": "Stewart Copeland",
"guitar": "Andy Summers",
"vocals": "Sting"
}
}
}
TASK [T02 - Select element based on band name] *********************************
ok: [localhost] => {
"msg": {
"bass": "Paul McCartney",
"drums": "Ringo Star",
"guitar": [
"George Harrison",
"John Lennon"
],
"vocals": [
"John Lennon",
"Paul McCartney",
"George Harrison",
"Ringo Star"
]
}
}
TASK [T03 - Show keys of highest level dictionary] *****************************
ok: [localhost] => {
"msg": [
"The Beatles",
"The Police",
"Rush",
"Led Zeppelin"
]
}
PLAY RECAP *********************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Notice there are no [ and ] at the first level in this final output because this is now a dictionary.
With a data structure like this, you could use the function "keys()" as shown in T03 if you just need to list the keys. You could also use the filter dict2item to run a loop through the dictionary.
Wrap up
From my experience, the important things to consider when dealing with lists, dictionaries, and combinations in real-life scenarios are:
- To understand the data structure: What is the data type for each part of the data?
- What is your strategy for using that data?
- Do you need to process all elements using a loop?
- Do you care only about certain elements (like the first element of a list or the element with the key "xyz" in your dictionary)?
- Are there elements in the data that are optional? Can a list be empty?
Have fun with your lists and dictionaries! (And sorry if I did not mention your favorite band.)
[ Learn how to manage your Linux environment for success. ]
About the author
Roberto Nozaki (RHCSA/RHCE/RHCA) is an Automation Principal Consultant at Red Hat Canada where he specializes in IT automation with Ansible. He has experience in the financial, retail, and telecommunications sectors, having performed different roles in his career, from programming in mainframe environments to delivering IBM/Tivoli and Netcool products as a pre-sales and post-sales consultant.
Roberto has been a computer and software programming enthusiast for over 35 years. He is currently interested in hacking what he considers to be the ultimate hardware and software: our bodies and our minds.
Roberto lives in Toronto, and when he is not studying and working with Linux and Ansible, he likes to meditate, play the electric guitar, and research neuroscience, altered states of consciousness, biohacking, and spirituality.
Browse by channel
Automation
The latest on IT automation for tech, teams, and environments
Artificial intelligence
Updates on the platforms that free customers to run AI workloads anywhere
Open hybrid cloud
Explore how we build a more flexible future with hybrid cloud
Security
The latest on how we reduce risks across environments and technologies
Edge computing
Updates on the platforms that simplify operations at the edge
Infrastructure
The latest on the world’s leading enterprise Linux platform
Applications
Inside our solutions to the toughest application challenges
Original shows
Entertaining stories from the makers and leaders in enterprise tech
Products
- Red Hat Enterprise Linux
- Red Hat OpenShift
- Red Hat Ansible Automation Platform
- Cloud services
- See all products
Tools
- Training and certification
- My account
- Customer support
- Developer resources
- Find a partner
- Red Hat Ecosystem Catalog
- Red Hat value calculator
- Documentation
Try, buy, & sell
Communicate
About Red Hat
We’re the world’s leading provider of enterprise open source solutions—including Linux, cloud, container, and Kubernetes. We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.
Select a language
Red Hat legal and privacy links
- About Red Hat
- Jobs
- Events
- Locations
- Contact Red Hat
- Red Hat Blog
- Diversity, equity, and inclusion
- Cool Stuff Store
- Red Hat Summit