Ansible selectattr Filter: Filter Lists by Attributes (Guide)
By Luca Berton · Published 2024-01-01 · Category: installation
How to use Ansible selectattr filter to filter lists by attributes. Select items matching conditions, combine with map and reject filters with examples.

How to Filter A List By Its Attributes in an Ansible Playbook?
I'm going to show you a live Playbook with some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible Pilot.See also: Automate Redmine Installation on Ubuntu LTS 22.04 with Ansible
selectattr filter in Ansible Playbook?
•{{ users|selectattr("is_active") }}
• {{ users|selectattr("email", "none") }}
Today we're talking about Ansible selectattr Jinja filter.
Filters a sequence of objects by applying a test to the specified attribute of each object, and only selecting the objects with the test succeeding.
If no test is specified, the attribute's value will be evaluated as a boolean.
The two examples explain how-to for a specific attribute or value using a users list example.
Links
• Data manipulation • Jinja selectattr## Playbook
How to filter a list by its attributes in an Ansible Playbook.
I'm going to use the selectattr filter to select only one information from Ansible System Information (Facts).
Specifically, I'm going to filter only for enabled features in a network interface (eth1).
code
---
- name: selectattr Playbook
hosts: all
gather_facts: true
tasks:
- name: all features
ansible.builtin.debug:
var: 'ansible_facts.eth1.features'
- name: filter enabled
ansible.builtin.debug:
msg: "{{ (ansible_facts.eth1.features | dict2items | selectattr('value', 'match', 'on') ) }}"
execution
ansible-pilot $ ansible-playbook -i virtualmachines/demo/inventory variables/selectattr.yml
PLAY [selectattr Playbook] ****************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [all features] *******************************************************************************
ok: [demo.example.com] => {
"ansible_facts.eth1.features": {
"esp_hw_offload": "off [fixed]",
"esp_tx_csum_hw_offload": "off [fixed]",
"fcoe_mtu": "off [fixed]",
"generic_receive_offload": "on",
"generic_segmentation_offload": "on",
"highdma": "off [fixed]",
"hw_tc_offload": "off [fixed]",
"l2_fwd_offload": "off [fixed]",
"large_receive_offload": "off [fixed]",
"loopback": "off [fixed]",
"netns_local": "off [fixed]",
"ntuple_filters": "off [fixed]",
"receive_hashing": "off [fixed]",
"rx_all": "off",
"rx_checksumming": "off",
"rx_fcs": "off",
"rx_gro_hw": "off [fixed]",
"rx_gro_list": "off",
"rx_udp_gro_forwarding": "off",
"rx_udp_tunnel_port_offload": "off [fixed]",
"rx_vlan_filter": "on [fixed]",
"rx_vlan_offload": "on",
"rx_vlan_stag_filter": "off [fixed]",
"rx_vlan_stag_hw_parse": "off [fixed]",
"scatter_gather": "on",
"tcp_segmentation_offload": "on",
"tls_hw_record": "off [fixed]",
"tls_hw_rx_offload": "off [fixed]",
"tls_hw_tx_offload": "off [fixed]",
"tx_checksum_fcoe_crc": "off [fixed]",
"tx_checksum_ip_generic": "on",
"tx_checksum_ipv4": "off [fixed]",
"tx_checksum_ipv6": "off [fixed]",
"tx_checksum_sctp": "off [fixed]",
"tx_checksumming": "on",
"tx_esp_segmentation": "off [fixed]",
"tx_fcoe_segmentation": "off [fixed]",
"tx_gre_csum_segmentation": "off [fixed]",
"tx_gre_segmentation": "off [fixed]",
"tx_gso_list": "off [fixed]",
"tx_gso_partial": "off [fixed]",
"tx_gso_robust": "off [fixed]",
"tx_ipxip4_segmentation": "off [fixed]",
"tx_ipxip6_segmentation": "off [fixed]",
"tx_lockless": "off [fixed]",
"tx_nocache_copy": "off",
"tx_scatter_gather": "on",
"tx_scatter_gather_fraglist": "off [fixed]",
"tx_sctp_segmentation": "off [fixed]",
"tx_tcp6_segmentation": "off [fixed]",
"tx_tcp_ecn_segmentation": "off [fixed]",
"tx_tcp_mangleid_segmentation": "off",
"tx_tcp_segmentation": "on",
"tx_tunnel_remcsum_segmentation": "off [fixed]",
"tx_udp_segmentation": "off [fixed]",
"tx_udp_tnl_csum_segmentation": "off [fixed]",
"tx_udp_tnl_segmentation": "off [fixed]",
"tx_vlan_offload": "on [fixed]",
"tx_vlan_stag_hw_insert": "off [fixed]",
"vlan_challenged": "off [fixed]"
}
}
TASK [filter enabled] *****************************************************************************
ok: [demo.example.com] => {
"msg": [
{
"key": "tx_checksumming",
"value": "on"
},
{
"key": "tx_checksum_ip_generic",
"value": "on"
},
{
"key": "scatter_gather",
"value": "on"
},
{
"key": "tx_scatter_gather",
"value": "on"
},
{
"key": "tcp_segmentation_offload",
"value": "on"
},
{
"key": "tx_tcp_segmentation",
"value": "on"
},
{
"key": "generic_segmentation_offload",
"value": "on"
},
{
"key": "generic_receive_offload",
"value": "on"
},
{
"key": "rx_vlan_offload",
"value": "on"
},
{
"key": "tx_vlan_offload",
"value": "on [fixed]"
},
{
"key": "rx_vlan_filter",
"value": "on [fixed]"
}
]
}
PLAY RECAP ****************************************************************************************
demo.example.com : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
ansible-pilot $
See also: Ansible selectattr & map Filters: Filter Data from Lists (Complete Guide)
Conclusion
Now you know how to Filter A List By Its Attributes in an Ansible Playbook.Basic selectattr
- vars:
users:
- { name: alice, role: admin, active: true }
- { name: bob, role: user, active: true }
- { name: charlie, role: admin, active: false }
debug:
msg:
- "Admins: {{ users | selectattr('role', 'eq', 'admin') | list }}"
- "Active: {{ users | selectattr('active') | list }}"
- "Admin names: {{ users | selectattr('role', 'eq', 'admin') | map(attribute='name') | list }}"
# ['alice', 'charlie']
# [alice_dict, bob_dict]
# ['alice', 'charlie']
See also: Ansible Scheduled Tasks: Cron Jobs & at Module for Timed Execution
Test Operators
| Operator | Example | Description |
|----------|---------|-------------|
| eq / equalto | selectattr('role', 'eq', 'admin') | Equals |
| ne | selectattr('status', 'ne', 'disabled') | Not equals |
| match | selectattr('name', 'match', '^web') | Regex match |
| search | selectattr('desc', 'search', 'important') | Regex search |
| in | selectattr('env', 'in', ['prod', 'staging']) | In list |
| defined | selectattr('email', 'defined') | Attribute exists |
| undefined | selectattr('phone', 'undefined') | Attribute missing |
| truthy | selectattr('active') | Truthy value |
rejectattr (Inverse)
# Exclude inactive users
- debug:
msg: "{{ users | rejectattr('active', 'eq', false) | list }}"
# Exclude admins
- debug:
msg: "{{ users | rejectattr('role', 'eq', 'admin') | map(attribute='name') | list }}"
Chain with map
- vars:
servers:
- { name: web1, env: prod, ip: 10.0.1.10 }
- { name: web2, env: prod, ip: 10.0.1.11 }
- { name: dev1, env: dev, ip: 10.0.2.10 }
set_fact:
prod_ips: "{{ servers | selectattr('env', 'eq', 'prod') | map(attribute='ip') | list }}"
# ['10.0.1.10', '10.0.1.11']
Complex Filtering
# Multiple conditions (chain selectattr)
- set_fact:
target: "{{ servers | selectattr('env', 'eq', 'prod') | selectattr('role', 'eq', 'web') | list }}"
# Select + sort
- set_fact:
sorted_prod: "{{ servers | selectattr('env', 'eq', 'prod') | sort(attribute='name') | list }}"
Practical Examples
Find hosts needing updates
- set_fact:
needs_update: "{{ host_info | selectattr('update_available', 'eq', true) | map(attribute='hostname') | list }}"
Filter packages by state
- set_fact:
installed: "{{ packages | selectattr('state', 'eq', 'installed') | map(attribute='name') | list }}"
missing: "{{ packages | rejectattr('state', 'eq', 'installed') | map(attribute='name') | list }}"
Find matching strings in list
# select (not selectattr) for simple lists
- set_fact:
python_packages: "{{ all_packages | select('match', '^python.*') | list }}"
FAQ
selectattr vs select?
•selectattr: Filter list of dicts by attribute
• select: Filter simple list by test
Why do I need | list at the end?
selectattr returns a generator. Pipe to list to materialize it, especially when using length or accessing by index.
Can I use selectattr in when conditions?
when: (users | selectattr('name', 'eq', 'admin') | list | length) > 0
Basic selectattr
- vars:
users:
- { name: alice, role: admin, active: true }
- { name: bob, role: user, active: true }
- { name: charlie, role: admin, active: false }
- { name: dave, role: user, active: false }
debug:
msg: "{{ users | selectattr('role', 'eq', 'admin') | list }}"
# [{"name": "alice", ...}, {"name": "charlie", ...}]
Common Tests
# Equal
"{{ users | selectattr('role', 'eq', 'admin') | list }}"
# Not equal
"{{ users | rejectattr('role', 'eq', 'admin') | list }}"
# Truthy (boolean true)
"{{ users | selectattr('active') | list }}"
# Defined
"{{ users | selectattr('email', 'defined') | list }}"
# Contains (string)
"{{ users | selectattr('name', 'contains', 'li') | list }}"
# Match (regex)
"{{ users | selectattr('name', 'match', '^a.*') | list }}"
# Greater than
"{{ servers | selectattr('cpu', 'gt', 4) | list }}"
# In list
"{{ users | selectattr('role', 'in', ['admin', 'superadmin']) | list }}"
selectattr + map
# Get names of active admin users
- debug:
msg: >-
{{ users
| selectattr('role', 'eq', 'admin')
| selectattr('active')
| map(attribute='name')
| list }}
# ["alice"]
rejectattr (Inverse)
# Users who are NOT admins
"{{ users | rejectattr('role', 'eq', 'admin') | list }}"
# Inactive users
"{{ users | rejectattr('active') | list }}"
Practical: Filter Services
- service_facts:
- set_fact:
running_services: >-
{{ ansible_facts.services.values()
| selectattr('state', 'eq', 'running')
| map(attribute='name')
| list }}
- debug:
msg: "Running: {{ running_services | length }} services"
Practical: Filter Inventory
# Hosts with enough memory
- set_fact:
big_hosts: >-
{{ groups['all']
| map('extract', hostvars)
| selectattr('ansible_memtotal_mb', 'defined')
| selectattr('ansible_memtotal_mb', 'gt', 4096)
| map(attribute='inventory_hostname')
| list }}
Chain Multiple Filters
- vars:
packages:
- { name: nginx, version: "1.24", installed: true, critical: true }
- { name: redis, version: "7.0", installed: true, critical: false }
- { name: postgres, version: "15", installed: false, critical: true }
set_fact:
missing_critical: >-
{{ packages
| selectattr('critical')
| rejectattr('installed')
| map(attribute='name')
| list }}
# ["postgres"]
With Loops
- user:
name: "{{ item.name }}"
state: present
loop: "{{ users | selectattr('active') | list }}"
become: true
FAQ
selectattr vs json_query?
selectattr is simpler — use for single-attribute filtering. json_query (JMESPath) handles complex nested queries. Start with selectattr, use json_query when needed.
How to filter by nested attribute?
selectattr doesn't support dot notation. Flatten the data first or use json_query:
"{{ data | json_query('[?server.status==`running`]') }}"
selectattr returns a generator?
Yes — always add | list at the end to materialize the result.
Related Articles
• template lookups in Ansible • managing inventory in Ansible • looping in Ansible playbooksCategory: installation
Watch the video: Ansible selectattr Filter: Filter Lists by Attributes (Guide) — Video Tutorial