AnsiblePilot — Ansible Automation Platform and Enterprise Ansible

AnsiblePilot covers Red Hat Ansible Automation Platform (AAP) and enterprise Ansible: install and upgrade paths, Event-Driven Ansible, security and day-2 operations, plus Luca Berton's books, videos and training.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 9 technical books published by Apress and Leanpub, 4 of them on Ansible, including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible selectattr Filter: Filter Lists by Attributes (Guide)

By Luca Berton · Published 2022-05-09 · 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.

Ansible selectattr Filter: Filter Lists by Attributes (Guide)

How to Filter A List By Its Attributes in an Ansible Playbook?

See also: Creating Custom Ansible Plugins to Fetch API Data Easily

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.

## 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 $

code with ❤️ in GitHub

See also: Ansible Scheduled Tasks: Cron Jobs & at Module for Timed Execution

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: Securely Automate Sudo Passwords in Ansible Playbooks

Test Operators

OperatorExampleDescription
eq / equaltoselectattr('role', 'eq', 'admin')Equals
neselectattr('status', 'ne', 'disabled')Not equals
matchselectattr('name', 'match', '^web')Regex match
searchselectattr('desc', 'search', 'important')Regex search
inselectattr('env', 'in', ['prod', 'staging'])In list
definedselectattr('email', 'defined')Attribute exists
undefinedselectattr('phone', 'undefined')Attribute missing
truthyselectattr('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.

Category: installation

Watch the video: Ansible selectattr Filter: Filter Lists by Attributes (Guide) — Video Tutorial

Browse all Ansible tutorials · AnsiblePilot Home