Ansible Search String in File: lineinfile & regex Guide
By Luca Berton · Published 2024-01-01 · Category: troubleshooting
How to search for strings in files with Ansible. Use lineinfile regex, check mode, shell grep, and slurp module to find and manage text patterns.

How to Search for a String in a File with Ansible?
I'm going to show you some simple Ansible code. I'm Luca Berton and welcome to today's episode of Ansible Pilot.See also: ansible.builtin.find Module: Search Files by Pattern, Size & Age (Guide)
Ansible module lineinfile
> ansible.builtin.lineinfile: insert, update and remove a single line of text in a file
Today we're talking about the Ansible module lineinfile.
The full name is ansible.builtin.lineinfile, which means that is part of the collection of modules "builtin" with ansible and shipped with it.
It's a module pretty stable and out for years and it supports a large variety of operating systems.
You are able to insert, update and remove a single line of text in a file.
Parameters
•path string - file path
• line string - text
• insertafter/insertbefore string - EOF/regular expression
• validate string - validation command
• create boolean - create if not exist
• state string - present/absent
• mode/owner/group - permission
• setype/seuser/selevel - SELinux
This module has some parameters to perform any tasks. The only required is "path", where you specify the filesystem path of the file you're going to edit. "line" is the line of text we would like to insert in the file, easy! By default, the text is going to be inserted at the end of the file, but we could personalize it in a specific position with insertafter/insertbefore. If there is any tool to validate the file we could specify in the validate parameter, very useful for configuration files. If the file does not exist we could also "create" it! Usually, we would like to insert a text line but we could also remove using state in conjunction with parameter absent. Let me also highlight that we could also specify some permissions or SELinux properties.
See also: Ansible Delete File: Remove Files & Directories (state=absent Guide)
Links
•ansible.builtin.lineinfile
Playbook
How to Search for a String in a File. How to search for a pattern in a file and return the result using only the Ansible built-in lineinfile module.code
---
- name: search Playbook
hosts: all
vars:
myfile: "/etc/ssh/sshd_config"
myline: 'PasswordAuthentication no'
become: true
tasks:
- name: string found
ansible.builtin.lineinfile:
name: "{{ myfile }}"
line: "{{ myline }}"
state: present
check_mode: true
register: conf
failed_when: (conf is changed) or (conf is failed)
string present
• remote host$ ssh devops@demo.example.com
[devops@demo ~]$ sudo su
[root@demo devops]# grep 'PasswordAuthentication no' /etc/ssh/sshd_config
PasswordAuthentication no
[root@demo devops]#
• Ansible execution
$ ansible-playbook -i virtualmachines/demo/inventory file_management/file_search.yml
PLAY [search Playbook] ********************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [string found] *******************************************************************************
ok: [demo.example.com]
PLAY RECAP ****************************************************************************************
demo.example.com : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
string different
• remote host$ ssh devops@demo.example.com
[devops@demo ~]$ sudo su
[root@demo devops]# vim /etc/ssh/sshd_config
[root@demo devops]# grep 'PasswordAuthentication' /etc/ssh/sshd_config
PasswordAuthentication yes
[root@demo devops]#
• Ansible execution
$ ansible-playbook -i virtualmachines/demo/inventory file_management/file_search.yml
PLAY [search Playbook] ********************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [string found] *******************************************************************************
fatal: [demo.example.com]: FAILED! => {"backup": "", "changed": true, "failed_when_result": true, "msg": "line added"}
PLAY RECAP ****************************************************************************************
demo.example.com : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
file not present
• remote host$ ssh devops@demo.example.com
[devops@demo ~]$ sudo su
[root@demo ssh]# ls -al /etc/ssh/sshd_config
ls: cannot access '/etc/ssh/sshd_config': No such file or directory
[root@demo ssh]#
• Ansible execution
$ ansible-playbook -i virtualmachines/demo/inventory file_management/file_search.yml
PLAY [search Playbook] ********************************************************************************
TASK [Gathering Facts] ****************************************************************************
ok: [demo.example.com]
TASK [string found] *******************************************************************************
fatal: [demo.example.com]: FAILED! => {"changed": false, "failed_when_result": true, "msg": "Destination /etc/ssh/sshd_config does not exist !", "rc": 257}
PLAY RECAP ****************************************************************************************
demo.example.com : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
See also: Ansible Check If Directory Exists: stat Module Guide
Conclusion
Now you know how to Search for a String in a File with Ansible and how you could use successfully in your Playbook.Search and Replace Line
- name: Update config setting
ansible.builtin.lineinfile:
path: /etc/myapp/config.conf
regexp: '^max_connections\s*='
line: 'max_connections = 200'
become: true
Check if String Exists
# Using grep
- command: grep -c "error" /var/log/myapp.log
register: grep_result
changed_when: false
failed_when: false
- debug:
msg: "Found {{ grep_result.stdout }} errors"
when: grep_result.rc == 0
lineinfile Patterns
# Ensure line exists
- lineinfile:
path: /etc/hosts
line: "10.0.1.50 db.internal"
# Replace matching line
- lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin'
line: 'PermitRootLogin no'
become: true
notify: restart sshd
# Insert after match
- lineinfile:
path: /etc/fstab
insertafter: '^# /data'
line: '/dev/sdb1 /data ext4 defaults 0 0'
# Insert before match
- lineinfile:
path: /etc/nginx/nginx.conf
insertbefore: '^}'
line: ' include /etc/nginx/conf.d/*.conf;'
# Remove matching line
- lineinfile:
path: /etc/hosts
regexp: 'old-server'
state: absent
Regex Search with search Test
- slurp: { src: /etc/myapp/config.yml }
register: config_raw
- set_fact:
config_content: "{{ config_raw.content | b64decode }}"
- debug: msg="Debug mode is enabled!"
when: config_content is search('debug:\s*true')
- debug: msg="SSL is configured"
when: config_content is search('ssl_cert.*\.pem')
Using find Module
# Find files containing a string
- name: Find configs with old hostname
command: grep -rl "old-hostname" /etc/
register: files_with_old
changed_when: false
failed_when: false
- name: Replace old hostname
replace:
path: "{{ item }}"
regexp: 'old-hostname'
replace: 'new-hostname'
loop: "{{ files_with_old.stdout_lines }}"
become: true
Replace Module (Multiple Matches)
# Replace ALL occurrences (lineinfile only handles one line)
- ansible.builtin.replace:
path: /etc/myapp/config.conf
regexp: 'localhost'
replace: '10.0.1.50'
become: true
lineinfile vs replace
| Feature | lineinfile | replace | |---------|-----------|---------| | Scope | Single line | All matches | | Insert | Yes (after/before) | No | | Ensure line | Yes | No | | Multi-line | No | Yes (with (?s)) | | Remove line | Yes (state: absent) | Replaces with empty |
Validate After Change
- lineinfile:
path: /etc/ssh/sshd_config
regexp: '^Port'
line: 'Port 2222'
validate: '/usr/sbin/sshd -t -f %s'
become: true
FAQ
lineinfile says "changed" but file looks the same?
Check for trailing whitespace differences. Use regexp to match existing line precisely.
How do I handle multi-line blocks?
Use blockinfile for multi-line insertions, or template for complex file management.
Can I search case-insensitively?
regexp: '(?i)^permit_root_login'
Search with lineinfile (check mode)
# Check if a line exists (don't change anything)
- lineinfile:
path: /etc/ssh/sshd_config
regexp: '^PermitRootLogin'
line: 'PermitRootLogin no'
check_mode: true
register: result
- debug:
msg: "Line {{ 'exists' if not result.changed else 'missing' }}"
Search with grep
- shell: grep -c 'error' /var/log/app.log
register: error_count
failed_when: false
changed_when: false
- debug:
msg: "Found {{ error_count.stdout }} errors"
Search with slurp
- slurp:
src: /etc/myapp/config.yml
register: config
- set_fact:
config_text: "{{ config.content | b64decode }}"
- debug:
msg: "Debug mode is enabled"
when: "'debug: true' in config_text"
Ensure Line Present
- lineinfile:
path: /etc/hosts
regexp: '^10\.0\.1\.10'
line: '10.0.1.10 db.example.com db'
become: true
Ensure Line Absent
- lineinfile:
path: /etc/crontab
regexp: 'old-backup-job'
state: absent
become: true
Replace with Regex
# Change a setting value
- lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin'
line: 'PermitRootLogin no'
become: true
notify: restart sshd
Insert After/Before
# Insert after a specific line
- lineinfile:
path: /etc/myapp/config
insertafter: '^\[database\]'
line: 'pool_size = 20'
# Insert before
- lineinfile:
path: /etc/myapp/config
insertbefore: '^\[logging\]'
line: 'cache_enabled = true'
Search Multiple Patterns
- shell: "grep -E '(ERROR|CRITICAL|FATAL)' /var/log/app.log | tail -20"
register: critical_errors
failed_when: false
changed_when: false
- debug:
msg: "{{ critical_errors.stdout_lines }}"
when: critical_errors.stdout_lines | length > 0
replace Module
# Replace all occurrences (not just one line)
- replace:
path: /etc/myapp/config
regexp: 'old-hostname\.example\.com'
replace: 'new-hostname.example.com'
become: true
blockinfile (Multi-Line)
- blockinfile:
path: /etc/ssh/sshd_config
marker: "# {mark} ANSIBLE MANAGED BLOCK"
block: |
PermitRootLogin no
PasswordAuthentication no
MaxAuthTries 3
become: true
FAQ
lineinfile vs replace vs blockinfile?
•lineinfile — single line operations (ensure present/absent)
• replace — regex find/replace across entire file
• blockinfile — manage multi-line blocks with markers
How to search without modifying?
Use check_mode: true with lineinfile, or use shell: grep with changed_when: false.
Can I search binary files?
No — use command: strings /path/file | grep pattern for binary files.
Related Articles
• skipping tasks with Ansible when • static and dynamic Ansible inventory • become and privilege escalation explained • desired-state Windows config with AnsibleCategory: troubleshooting
Watch the video: Ansible Search String in File: lineinfile & regex Guide — Video Tutorial