Skip to content

Comparison Numeric Tests


Back in the collections chapter, select('even') and selectattr('status', 'equalto', 'running') used named tests without explaining why they exist as words instead of ordinary operators. This chapter closes that loop.

is equalto

when: status is equalto 'running'

Functionally identical to status == 'running'. So why does a named version exist at all? Because select and selectattr need to accept a comparison as an argument — you can’t hand a filter an inline == expression, but you can hand it the string 'equalto' plus a value to compare against. Named tests are what make that possible.

is gt, is ge, is lt, is le

Named equivalents of >, >=, <, <= — same reasoning, same purpose:

when: age is gt 18
vars:
  ports: [22, 80, 443, 3000, 8080]
tasks:
  - name: Select high ports
    ansible.builtin.debug:
      msg: "{{ ports | select('gt', 1024) | list }}"
[3000, 8080]

Here’s the full picture behind that Chapter 5 example, finally explained: select('gt', 1024) couldn’t be written as select(port > 1024) — there’s no single value to compare against yet at that point, just a filter waiting for a test name and an argument. 'gt' plus 1024 is exactly that.

is even And is odd

The same tests used unexplained back in the collections chapter:

msg: "{{ [1, 2, 3, 4, 5, 6] | select('even') | list }}"
[2, 4, 6]

Using These Same Tests With when:

Nothing stops you from using named tests directly in a when:, even outside a filter:

when: retry_count is gt 3
when: port_number is even

Whether you reach for is gt 3 or > 3 in a plain when: is mostly a matter of taste — both work identically there. Where named tests stop being optional is inside select/selectattr/reject/rejectattr, which have no other way to accept a comparison at all.

Revisiting select/selectattr Now That You Know What’s Inside

vars:
  servers:
    - name: web1
      port: 8080
    - name: db1
      port: 22
tasks:
  - name: Select servers with high ports
    ansible.builtin.debug:
      msg: "{{ servers | selectattr('port', 'gt', 1024) | map(attribute='name') | list }}"
["web1"]

Same pipeline shape as the collections chapter’s selectattr + map example — now with a full understanding of what 'gt' inside it actually is.

A Gotcha: Numeric Tests On Strings

This is the same trap from the numbers and lists chapters, showing up again in a third place:

vars:
  port_str: "500"
tasks:
  - name: This fails
    ansible.builtin.debug:
      msg: "{{ port_str is gt 100 }}"

Comparing a string to a number fails, exactly the way sorting a mixed-type list failed back in the lists chapter. Convert first:

msg: "{{ port_str | int is gt 100 }}"
True

Best Practices

  • Use named tests (equalto, gt, and so on) when a comparison needs to be passed as an argument — inside select, selectattr, reject, or rejectattr. In a plain when:, ordinary operators (==, >) work just as well and are often more familiar.
  • Convert with | int/| float before a numeric test, exactly the same discipline established for arithmetic — a numeric-looking string is still a string until you say otherwise.
Last updated on