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?
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
pathstring - file pathlinestring - textinsertafter/insertbeforestring - EOF/regular expressionvalidatestring - validation commandcreateboolean - create if not existstatestring - present/absentmode/owner/group- permissionsetype/seuser/selevel- SELinux
See also: Ansible Delete File: Remove Files & Directories (state=absent Guide)
Links
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=0string 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=0file 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=0See 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: trueCheck 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 == 0lineinfile 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: absentRegex 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: trueReplace 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: truelineinfile 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: trueFAQ
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: trueEnsure Line Absent
- lineinfile:
path: /etc/crontab
regexp: 'old-backup-job'
state: absent
become: trueReplace with Regex
# Change a setting value
- lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin'
line: 'PermitRootLogin no'
become: true
notify: restart sshdInsert 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 > 0replace Module
# Replace all occurrences (not just one line)
- replace:
path: /etc/myapp/config
regexp: 'old-hostname\.example\.com'
replace: 'new-hostname.example.com'
become: trueblockinfile (Multi-Line)
- blockinfile:
path: /etc/ssh/sshd_config
marker: "# {mark} ANSIBLE MANAGED BLOCK"
block: |
PermitRootLogin no
PasswordAuthentication no
MaxAuthTries 3
become: trueFAQ
lineinfile vs replace vs blockinfile?
lineinfile— single line operations (ensure present/absent)replace— regex find/replace across entire fileblockinfile— 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
Category: troubleshooting
Watch the video: Ansible Search String in File: lineinfile & regex Guide — Video Tutorial