AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub 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 regex_replace Filter: Find & Replace with Regex (Complete Guide)

By Luca Berton · Published 2024-01-01 · Category: installation

How to find and replace text with regex in Ansible using regex_replace filter. Pattern matching, capture groups, string substitution.

The regex_replace filter in Ansible lets you perform regex-based find-and-replace operations on strings directly in your playbooks. It's essential for transforming hostnames, cleaning data, rewriting configuration values, and manipulating text without external tools.

Basic Syntax

{{ string | regex_replace(pattern, replacement) }}
pattern — Python regular expression to match • replacement — Replacement string (supports backreferences \\1, \\2)
- name: Simple regex replace
  ansible.builtin.debug:
    msg: "{{ 'Hello World' | regex_replace('World', 'Ansible') }}"
  # Output: "Hello Ansible"

See also: Ansible default() Filter: Set Fallback Values for Undefined Variables

Common Use Cases

Remove Characters from a String

- name: Remove all non-alphanumeric characters
  ansible.builtin.debug:
    msg: "{{ 'web-server_01.example.com' | regex_replace('[^a-zA-Z0-9]', '') }}"
  # Output: "webserver01examplecom"

- name: Remove trailing whitespace ansible.builtin.debug: msg: "{{ my_string | regex_replace('\\s+$', '') }}"

- name: Remove comments from config line ansible.builtin.debug: msg: "{{ 'max_connections = 200 # default is 100' | regex_replace('\\s*#.*$', '') }}" # Output: "max_connections = 200"

Extract and Transform with Capture Groups

- name: Swap first and last name
  ansible.builtin.debug:
    msg: "{{ 'Berton, Luca' | regex_replace('^(\\w+),\\s*(\\w+)$', '\\2 \\1') }}"
  # Output: "Luca Berton"

- name: Extract version number ansible.builtin.debug: msg: "{{ 'ansible-core-2.16.0.tar.gz' | regex_replace('^.*-(\\d+\\.\\d+\\.\\d+).*$', '\\1') }}" # Output: "2.16.0"

- name: Reformat date (MM/DD/YYYY → YYYY-MM-DD) ansible.builtin.debug: msg: "{{ '04/12/2026' | regex_replace('(\\d{2})/(\\d{2})/(\\d{4})', '\\3-\\1-\\2') }}" # Output: "2026-04-12"

Add Prefix or Suffix

- name: Add prefix to each word
  ansible.builtin.debug:
    msg: "{{ 'nginx redis postgres' | regex_replace('(\\w+)', 'pkg_\\1') }}"
  # Output: "pkg_nginx pkg_redis pkg_postgres"

- name: Wrap string in quotes ansible.builtin.debug: msg: "{{ my_value | regex_replace('^(.*)$', '\"\\1\"') }}"

Clean Hostnames and URLs

vars:
  fqdn: "web-server-01.prod.example.com"

tasks: - name: Extract short hostname ansible.builtin.debug: msg: "{{ fqdn | regex_replace('\\..*$', '') }}" # Output: "web-server-01"

- name: Extract domain ansible.builtin.debug: msg: "{{ fqdn | regex_replace('^[^.]+\\.', '') }}" # Output: "prod.example.com"

- name: Convert hostname to underscore format ansible.builtin.debug: msg: "{{ fqdn | regex_replace('[.-]', '_') }}" # Output: "web_server_01_prod_example_com"

Case-Insensitive Matching

Use the (?i) flag at the start of the pattern:

- name: Replace case-insensitively
  ansible.builtin.debug:
    msg: "{{ 'Hello WORLD hello World' | regex_replace('(?i)hello', 'hi') }}"
  # Output: "hi WORLD hi World"

See also: Ansible map Filter: Extract Attributes from Lists (Complete Guide)

Multiline Patterns

Use (?m) for multiline mode (where ^ and $ match line boundaries) and (?s) for dotall mode (where . matches newlines):

- name: Remove comment lines from multiline string
  ansible.builtin.debug:
    msg: "{{ my_config | regex_replace('(?m)^#.*\\n?', '') }}"

- name: Replace content between markers ansible.builtin.debug: msg: "{{ content | regex_replace('(?s)BEGIN.*?END', 'REPLACED') }}"

Use with map for List Transformation

vars:
  servers: ['web-01', 'web-02', 'db-01']

tasks: - name: Convert hyphens to underscores in all items ansible.builtin.debug: msg: "{{ servers | map('regex_replace', '-', '_') | list }}" # Output: ['web_01', 'web_02', 'db_01']

- name: Add domain to all hostnames ansible.builtin.debug: msg: "{{ servers | map('regex_replace', '$', '.example.com') | list }}" # Output: ['web-01.example.com', 'web-02.example.com', 'db-01.example.com']

See also: Ansible Jinja2 Filters: Transform Data in Playbooks (Complete Reference)

Use in Templates (Jinja2)

{% for host in groups['all'] %}
{{ host | regex_replace('\\..*$', '') }} ansible_host={{ hostvars[host]['ansible_host'] }}
{% endfor %}

Use in Conditionals

- name: Only run for production servers
  ansible.builtin.debug:
    msg: "Production server detected"
  when: inventory_hostname | regex_replace('^.*-', '') == 'prod'

regex_replace vs replace

| Feature | replace | regex_replace | |---------|-----------|-----------------| | Pattern type | Literal string | Regular expression | | Capture groups | ❌ | ✅ (\\1, \\2) | | Flags (case, multiline) | ❌ | ✅ ((?i), (?m)) | | Performance | Faster | Slightly slower | | Use when | Simple literal replacement | Pattern matching needed |

# Simple literal — use replace
{{ 'hello-world' | replace('-', '_') }}

# Pattern matching — use regex_replace {{ 'hello-world-123' | regex_replace('-\\d+$', '') }}

regex_replace vs regex_search

regex_replace — Replaces matched text with something else (transformation) • regex_search — Extracts the first match from a string (extraction)
# regex_replace: transform the string
{{ 'version: 2.16.0' | regex_replace('^version:\\s*', '') }}
# Output: "2.16.0"

# regex_search: extract a match {{ 'version: 2.16.0' | regex_search('\\d+\\.\\d+\\.\\d+') }} # Output: "2.16.0"

Real-World Playbook Examples

Sanitize User Input

- name: Clean user-provided hostname
  ansible.builtin.set_fact:
    clean_hostname: "{{ raw_hostname | regex_replace('[^a-zA-Z0-9.-]', '') | regex_replace('^-+|-+$', '') | lower }}"

Generate Config from Inventory

- name: Build upstream block for nginx
  ansible.builtin.copy:
    content: |
      upstream backend {
      {% for host in groups['app_servers'] %}
          server {{ hostvars[host]['ansible_default_ipv4']['address'] }}:{{ app_port | default(8080) }};  # {{ host | regex_replace('\\..*$', '') }}
      {% endfor %}
      }
    dest: /etc/nginx/conf.d/upstream.conf

Normalize Package Names

- name: Remove version suffixes from package list
  ansible.builtin.set_fact:
    package_names: "{{ installed_packages | map('regex_replace', '-\\d+[.\\d]*.*$', '') | unique | list }}"

Convert Between Naming Conventions

- name: CamelCase to snake_case
  ansible.builtin.debug:
    msg: "{{ 'MyVariableName' | regex_replace('([A-Z])', '_\\1') | regex_replace('^_', '') | lower }}"
  # Output: "my_variable_name"

- name: snake_case to kebab-case ansible.builtin.debug: msg: "{{ 'my_variable_name' | regex_replace('_', '-') }}" # Output: "my-variable-name"

Escaping Special Characters

When your pattern contains special regex characters, escape them with \\:

# Match literal dots
{{ hostname | regex_replace('\\.', '_') }}

# Match literal brackets {{ text | regex_replace('\\[(.+?)\\]', '(\\1)') }}

# Match literal dollar sign {{ price | regex_replace('\\$', 'USD ') }}

FAQ

How do I replace text with regex in Ansible?

Use the regex_replace filter: {{ my_string | regex_replace('pattern', 'replacement') }}. The pattern is a Python regular expression. Use \\1, \\2 for capture group backreferences in the replacement string.

What is the difference between replace and regex_replace in Ansible?

The replace filter matches literal strings only. The regex_replace filter matches regular expression patterns, supports capture groups (\\1), and allows flags like (?i) for case-insensitive matching. Use replace for simple text; use regex_replace when you need pattern matching.

How do I use capture groups in regex_replace?

Wrap parts of your pattern in parentheses to create capture groups, then reference them as \\1, \\2 in the replacement: {{ 'John Doe' | regex_replace('^(\\w+) (\\w+)$', '\\2, \\1') }} outputs Doe, John.

How do I do case-insensitive regex replace in Ansible?

Add (?i) at the start of your pattern: {{ text | regex_replace('(?i)error', 'warning') }}. This makes the entire pattern case-insensitive.

Can I use regex_replace in a loop with map?

Yes, use map to apply regex_replace to every item in a list: {{ my_list | map('regex_replace', 'old', 'new') | list }}.

Conclusion

The regex_replace filter is essential for string transformation in Ansible: • Simple replacements: string | regex_replace('pattern', 'new')Capture groups: Use () in pattern, \\1 in replacement • Case-insensitive: Add (?i) prefix to pattern • List transformation: Chain with map filter • Choose wisely: Use replace for literals, regex_replace for patterns

Related Articles

Ansible regex_search Filter: Pattern Matching & Text Extraction GuideFilter a List by Its Attributes: Ansible selectattr FilterEdit Single Line Text: Ansible Module lineinfileAnsible map Filter: Extract Attributes from ListsAnsible split Filter Complete Guide

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home