Skip to content

Working With Numbers


Last chapter ended with a promise: + does something completely correct once you’re actually working with numbers, rather than trying to concatenate strings with it. This chapter covers that, along with the single most common source of numeric bugs in Ansible playbooks — a value that looks like a number, but is secretly still a string.

Basic Arithmetic

Jinja2 supports the arithmetic operators you’d expect:

vars:
  a: 10
  b: 3
tasks:
  - name: Show arithmetic
    ansible.builtin.debug:
      msg: "{{ a + b }} {{ a - b }} {{ a * b }} {{ a / b }} {{ a // b }} {{ a % b }}"
13 7 30 3.3333333333333335 3 1

In order: addition, subtraction, multiplication, division, floor division, and modulo (remainder). Two worth calling out specifically: / always produces a floating-point result, even when both sides are whole numbers — 10 / 3 is 3.333..., not 3. // is floor division, giving you the whole-number result you might have expected from /10 // 3 is 3.

Rounding With round

msg: "{{ 3.14159 | round(2) }}"
3.14

round without an argument rounds to the nearest whole number — but still returns it as a float (3.0, not 3). If you specifically need a clean integer afterward, chain | int on the end:

msg: "{{ 3.7 | round | int }}"
4

Converting Types With int And float

int and float convert a value — very often a string — into an actual number:

msg: "{{ '42' | int + 8 }}"
50

This matters more than it might look like at first glance, for a reason covered fully in this chapter’s gotcha section: values from a registered command’s stdout, environment variables, and command-line extra vars all arrive as strings, even when every character in them is a digit.

abs

msg: "{{ -5 | abs }}"
5

A Gotcha: Strings That Look Like Numbers

Here’s the dangerous one — and it’s dangerous specifically because it fails silently, with a plausible-looking wrong answer, rather than throwing an obvious error.

vars:
  count_str: "5"
  other_str: "3"
tasks:
  - name: This silently does the wrong thing
    ansible.builtin.debug:
      msg: "{{ count_str + other_str }}"
53

Not 8"53". Both values are strings, and + on two strings concatenates them, exactly the same way it would in Python underneath. There’s no error here at all — just a confidently wrong number, easy to miss if you’re not specifically checking the result.

    - name: This does what you actually want
      ansible.builtin.debug:
        msg: "{{ count_str | int + other_str | int }}"
8

Converting both sides with | int first gives the correct numeric addition.

Warning

This is exactly the trap waiting for anyone using a registered task’s stdout in arithmetic. register always captures stdout as a string, no matter how numeric the command’s actual output looked — wc -l’s output, a line count, a byte count, all of it arrives as text. Get in the habit of converting with | int (or | float) before doing any arithmetic on a registered value, every time, without exception.

Best Practices

  • Convert with | int or | float before any arithmetic on a value that might be a string — especially anything from register, an environment variable, or a command-line extra var (-e), all of which are strings by default regardless of what they look like.
  • Remember / always returns a float. Use // when you specifically want a whole-number result from division.
  • Chain | round | int when you need a genuinely clean integer, not just a whole-numbered float.
Last updated on