If you are not familiar with modules, check out Ansible - Getting Started with Modules.
There are a few different modules that can be used to modify a file.
- blockinfile can be used to append, change, or remove a block of lines in a file
- lineinfile can be used to append, change, or remove one or more lines in a file (this article)
- replace can be used to change or remove one or more lines in a file.
By default, the line will be appended at the end of the file if the file does not already contain the line.
---
- hosts: all
tasks:
- name: append 'Hello World' to /tmp/foo.txt
lineinfile:
path: /tmp/foo.txt
line: "Hello World"
...
If the target file exists and does not contain "Hello World", "changed" should be returned.
TASK [append 'Hello World' to /tmp/foo.txt]
changed: [server1.example.com]
If the target file exists and already contains line "Hello World", "ok" should be returned and Hello World will not be appended to the file.
TASK [append 'Hello World' to /tmp/foo.txt]
ok: [server1.example.com]
The debug module can make this even more apparent.
---
- hosts: all
tasks:
- name: append 'Hello World' to /tmp/foo.txt
lineinfile:
path: /tmp/foo.txt
line: "Hello World"
register: out
- debug:
var: out
...
If the target file exists and does not contain "Hello World", "changed" should be true and msg should contain "line added".
ok: [server1.example.com] => {
"out": {
"backup": "",
"changed": true,
"diff": [
{
"after": "",
"after_header": "/tmp/foo.txt (content)",
"before": "",
"before_header": "/tmp/foo.txt (content)"
},
{
"after_header": "/tmp/foo.txt (file attributes)",
"before_header": "/tmp/foo.txt (file attributes)"
}
],
"failed": false,
"msg": "line added"
}
}
If the target file exists and already contains line "Hello World", changed should be false and msg should be empty.
ok: [server1.example.com] => {
"out": {
"backup": "",
"changed": false,
"diff": [
{
"after": "",
"after_header": "/tmp/foo.txt (content)",
"before": "",
"before_header": "/tmp/foo.txt (content)"
},
{
"after_header": "/tmp/foo.txt (file attributes)",
"before_header": "/tmp/foo.txt (file attributes)"
}
],
"failed": false,
"msg": ""
}
}
AVOID TROUBLE
If the target file does not exist, lineinfile may cause the play to fail fatal.
For this reason, you will almost always want to use the create: true parameter, so that the file is created if it does not exist. Or use the stat module to determine if the file exists, and then used the when parameter to only execute the task when the file exists.
fatal: [server1.example.com]: FAILED! => {
"changed": false,
"msg": "Destination /tmp/foo.txt does not exist !",
"rc": 257
}
The create option can be used to create the file if it does not exist.
Or the file module can be used to create the file.
Or the stat module can be used to determine if the file exists and the when parameter can be used to only execute the task when the file exists.
Or ignore_errors can be used.
---
- hosts: all
tasks:
- name: append 'Hello World' to /tmp/foo.txt
lineinfile:
path: /tmp/foo.txt
line: "Hello World"
create: true
...
with_items can be used to append multiple lines to the file.
---
- hosts: all
tasks:
- name: append lines to /tmp/foo.txt
lineinfile:
path: /tmp/foo.txt
line: "{{ item }}"
create: true
with_items:
- Hello World
- foo
- bar
...
insertafter: EOF can be used to append new lines to the bottom of the file which is the default behavior thus this parameter isn't required.
- name: append 'World' to the end of /tmp/foo.txt
lineinfile:
path: /tmp/foo.txt
line: World
insertafter: EOF
Or, you can use a regular expression. Let's say foo.txt contains the following:
Hello
World
The following will append "example" after the line beginning with Hello.
---
- hosts: all
tasks:
- name: append 'example' after line beginning with 'Hello'
lineinfile:
path: /tmp/foo.txt
line: example
insertafter: ^Hello
...
Running this play should update foo.txt to have the following.
Hello
example
World
insertbefore: BOF can be used to append to the beginning of the file (BOF).
---
- hosts: all
tasks:
- name: append 'World' to the beginning of /tmp/foo.txt
lineinfile:
path: /tmp/foo.txt
line: World
insertbefore: BOF
...
In this example, state: present is used so that "new line" is appended if the file does not currently contain any lines matching "new line" which is the default behavior thus this parameter isn't required. If there is already a line matching "new line", nothing will be appended.
- name: append new line EOF if doesn't exist
lineinfile:
path: /tmp/foo.txt
line: "new line"
state: present
In this example, line is used to replace the last line containing "old line" with "new line". If the file contains two or more lines containing "old line", only the last line containing "old line" will be updated to "new line". For this reason, the replace module is typically used to update a text in a file, as the replace module would replace every line containing "old line" with "new line".
- name: replace old line with new line
lineinfile:
path: /tmp/foo.txt
regexp: "old line"
line: "new line"
Append to an existing line
Let's say foo.txt contains "Hello World". Here is how you would append "example" after Hello World.
- lineinfile:
path: /tmp/foo.txt
backrefs: true
regexp: '^(old line)$'
line: '\1 example'
Remove lines
regexp and state: absent can be used to remove lines matching the regular expression. In this example, lines containing "Hello World" will be removed from the /tmp/foo.txt file.
- name: remove new line
lineinfile:
path: /tmp/foo.txt
regexp: "Hello World"
state: absent
Did you find this article helpful?
If so, consider buying me a coffee over at