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 1In 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.14round 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 }}"4Converting Types With int And float
int and float convert a value — very often a string — into an actual number:
msg: "{{ '42' | int + 8 }}"50This 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 }}"5A 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 }}"53Not 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 }}"8Converting 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
| intor| floatbefore any arithmetic on a value that might be a string — especially anything fromregister, 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 | intwhen you need a genuinely clean integer, not just a whole-numbered float.