Only check whether a line present in a file (ansible) - ansible

In ansible, I need to check whether a particular line present in a file or not. Basically, I need to convert the following command to an ansible task. My goal is to only check.
grep -Fxq "127.0.0.1" /tmp/my.conf

Use check_mode, register and failed_when in concert. This fails the task if the lineinfile module would make any changes to the file being checked. Check_mode ensures nothing will change even if it otherwise would.
- name: "Ensure /tmp/my.conf contains '127.0.0.1'"
lineinfile:
name: /tmp/my.conf
line: "127.0.0.1"
state: present
check_mode: yes
register: conf
failed_when: (conf is changed) or (conf is failed)

- name: Check whether /tmp/my.conf contains "127.0.0.1"
command: grep -Fxq "127.0.0.1" /tmp/my.conf
register: checkmyconf
check_mode: no
ignore_errors: yes
changed_when: no
- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: checkmyconf.rc == 0
Update 2017-08-28: Older Ansible versions need to use always_run: yes instead of check_mode: no.

User robo's regexp & absent method is quite clean, so I've fleshed it out here for easy use and added improvements from comments by #assylias and #Olivier:
- name: Ensure /tmp/my.conf contains 127.0.0.1
lineinfile:
path: /tmp/my.conf
regexp: '^127\.0\.0\.1.*whatever'
state: absent
check_mode: yes
changed_when: false
register: out
- debug:
msg: "Yes, line exists."
when: out.found
- debug:
msg: "Line does NOT exist."
when: not out.found

With the accepted solution, even though you ignore errors, you will still get ugly red error output on the first task if there is no match:
TASK: [Check whether /tmp/my.conf contains "127.0.0.1"] ***********************
failed: [localhost] => {"changed": false, "cmd": "grep -Fxq "127.0.0.1" /tmp/my.conf", "delta": "0:00:00.018709", "end": "2015-09-27 17:46:18.252024", "rc": 1, "start": "2015-09-27 17:46:18.233315", "stdout_lines": [], "warnings": []}
...ignoring
If you want less verbose output, you can use awk instead of grep. awk won't return an error on a non-match, which means the first check task below won't error regardless of a match or non-match:
- name: Check whether /tmp/my.conf contains "127.0.0.1"
command: awk /^127.0.0.1$/ /tmp/my.conf
register: checkmyconf
changed_when: False
- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: checkmyconf.stdout | match("127.0.0.1")
Notice that my second task uses the match filter as awk returns the matched string if it finds a match.
The alternative above will produce the following output regardless of whether the check task has a match or not:
TASK: [Check whether /tmp/my.conf contains "127.0.0.1"] ***********************
ok: [localhost]
IMHO this is a better approach as you won't ignore other errors in your first task (e.g. if the specified file did not exist).

Use ansible lineinfile command, but this command will update the file with the line if it does not exists.
- lineinfile: dest=/tmp/my.conf line='127.0.0.1' state=present

Another way is to use the "replace module" then "lineinfile module".
The algo is closed to the one used when you want to change the values of two variables.
First, use "replace module" to detect if the line you are looking for is here and change it with the something else. (Like same line + something at the end).
Then if "replace" is true, It means your line is here then replace the new line with a particularity, with the new line looking.
Else the line you are looking for is not here.
Example:
# Vars
- name: Set parameters
set_fact:
newline : "hello, i love ansible"
lineSearched : "hello"
lineModified : "hello you"
# Tasks
- name: Try to replace the line
replace:
dest : /dir/file
replace : '{{ lineModified }} '
regexp : '{{ lineSearched }}$'
backup : yes
register : checkIfLineIsHere
- name: Line is here, change it
lineinfile:
state : present
dest : /dir/file
line : '{{ newline }}'
regexp : '{{ lineModified }}$'
when: checkIfLineIsHere.changed
If the file contains "hello", it will become "hello you" then "hello, i love ansible" at the end.
If the file content doesn't contain "hello", the file is not modified.
With the same idea, you can do something if the lineSearched is here:
# Vars
- name: Set parameters
set_fact:
newline : "hello, i love ansible"
lineSearched : "hello"
lineModified : "hello you"
# Tasks
- name: Try to replace the line
replace:
dest : /dir/file
replace : '{{ lineModified }} '
regexp : '{{ lineSearched }}$'
backup : yes
register : checkIfLineIsHere
# If the line is here, I want to add something.
- name: If line is here, do something
lineinfile:
state : present
dest : /dir/file
line : '{{ newline }}'
regexp : ''
insertafter: EOF
when: checkIfLineIsHere.changed
# But I still want this line in the file, Then restore it
- name: Restore the searched line.
lineinfile:
state : present
dest : /dir/file
line : '{{ lineSearched }}'
regexp : '{{ lineModified }}$'
when: checkIfLineIsHere.changed
If the file contains "hello", the line will still contain "hello" and "hello, i love ansible" at the end.
If the file content doesn't contain "hello", the file is not modified.

You can use the file plugin for this scenario.
To set a fact you can use in other tasks ... this works.
- name: Check whether /tmp/my.conf contains "127.0.0.1"
set_fact:
myconf: "{{ lookup('file', '/tmp/my.conf') }}"
ignore_errors: yes
- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: "'127.0.0.1' in myconf"
To check the file content as a condition of a task ... this should work.
- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: "'127.0.0.1' in lookup('file', '/tmp/my.conf')"

Another solution, also useful for other purposes is to loop over the contents of the file, line by line
- name: get the file
slurp:
src: /etc/locale.gen
register: slurped_file
- name: initialize the matches list
set_fact:
MATCHES: []
- name: collect matches in a list
set_fact:
MATCHES: "{{ MATCHES + [line2match] }}"
loop: "{{ file_lines }}"
loop_control:
loop_var: line2match
vars:
- decode_content: "{{ slurped_file.content | b64decode }}"
- file_lines: "{{ decode_content.split('\n') }}"
when: '"BE" in line2match'
- name: report matches if any
debug:
msg: "Found {{ MATCHES | length }} matches\n{{ MATCHES }}"
when: 'listlen | int > 0'
vars:
listlen: "{{ MATCHES | length }}"
This mechanism can be use to get a specific value from a matched line if you use it for example with the jinja regex_replace filter

Related

How to compare the contain of my file with ansible? [duplicate]

In ansible, I need to check whether a particular line present in a file or not. Basically, I need to convert the following command to an ansible task. My goal is to only check.
grep -Fxq "127.0.0.1" /tmp/my.conf
Use check_mode, register and failed_when in concert. This fails the task if the lineinfile module would make any changes to the file being checked. Check_mode ensures nothing will change even if it otherwise would.
- name: "Ensure /tmp/my.conf contains '127.0.0.1'"
lineinfile:
name: /tmp/my.conf
line: "127.0.0.1"
state: present
check_mode: yes
register: conf
failed_when: (conf is changed) or (conf is failed)
- name: Check whether /tmp/my.conf contains "127.0.0.1"
command: grep -Fxq "127.0.0.1" /tmp/my.conf
register: checkmyconf
check_mode: no
ignore_errors: yes
changed_when: no
- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: checkmyconf.rc == 0
Update 2017-08-28: Older Ansible versions need to use always_run: yes instead of check_mode: no.
User robo's regexp & absent method is quite clean, so I've fleshed it out here for easy use and added improvements from comments by #assylias and #Olivier:
- name: Ensure /tmp/my.conf contains 127.0.0.1
lineinfile:
path: /tmp/my.conf
regexp: '^127\.0\.0\.1.*whatever'
state: absent
check_mode: yes
changed_when: false
register: out
- debug:
msg: "Yes, line exists."
when: out.found
- debug:
msg: "Line does NOT exist."
when: not out.found
With the accepted solution, even though you ignore errors, you will still get ugly red error output on the first task if there is no match:
TASK: [Check whether /tmp/my.conf contains "127.0.0.1"] ***********************
failed: [localhost] => {"changed": false, "cmd": "grep -Fxq "127.0.0.1" /tmp/my.conf", "delta": "0:00:00.018709", "end": "2015-09-27 17:46:18.252024", "rc": 1, "start": "2015-09-27 17:46:18.233315", "stdout_lines": [], "warnings": []}
...ignoring
If you want less verbose output, you can use awk instead of grep. awk won't return an error on a non-match, which means the first check task below won't error regardless of a match or non-match:
- name: Check whether /tmp/my.conf contains "127.0.0.1"
command: awk /^127.0.0.1$/ /tmp/my.conf
register: checkmyconf
changed_when: False
- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: checkmyconf.stdout | match("127.0.0.1")
Notice that my second task uses the match filter as awk returns the matched string if it finds a match.
The alternative above will produce the following output regardless of whether the check task has a match or not:
TASK: [Check whether /tmp/my.conf contains "127.0.0.1"] ***********************
ok: [localhost]
IMHO this is a better approach as you won't ignore other errors in your first task (e.g. if the specified file did not exist).
Use ansible lineinfile command, but this command will update the file with the line if it does not exists.
- lineinfile: dest=/tmp/my.conf line='127.0.0.1' state=present
Another way is to use the "replace module" then "lineinfile module".
The algo is closed to the one used when you want to change the values of two variables.
First, use "replace module" to detect if the line you are looking for is here and change it with the something else. (Like same line + something at the end).
Then if "replace" is true, It means your line is here then replace the new line with a particularity, with the new line looking.
Else the line you are looking for is not here.
Example:
# Vars
- name: Set parameters
set_fact:
newline : "hello, i love ansible"
lineSearched : "hello"
lineModified : "hello you"
# Tasks
- name: Try to replace the line
replace:
dest : /dir/file
replace : '{{ lineModified }} '
regexp : '{{ lineSearched }}$'
backup : yes
register : checkIfLineIsHere
- name: Line is here, change it
lineinfile:
state : present
dest : /dir/file
line : '{{ newline }}'
regexp : '{{ lineModified }}$'
when: checkIfLineIsHere.changed
If the file contains "hello", it will become "hello you" then "hello, i love ansible" at the end.
If the file content doesn't contain "hello", the file is not modified.
With the same idea, you can do something if the lineSearched is here:
# Vars
- name: Set parameters
set_fact:
newline : "hello, i love ansible"
lineSearched : "hello"
lineModified : "hello you"
# Tasks
- name: Try to replace the line
replace:
dest : /dir/file
replace : '{{ lineModified }} '
regexp : '{{ lineSearched }}$'
backup : yes
register : checkIfLineIsHere
# If the line is here, I want to add something.
- name: If line is here, do something
lineinfile:
state : present
dest : /dir/file
line : '{{ newline }}'
regexp : ''
insertafter: EOF
when: checkIfLineIsHere.changed
# But I still want this line in the file, Then restore it
- name: Restore the searched line.
lineinfile:
state : present
dest : /dir/file
line : '{{ lineSearched }}'
regexp : '{{ lineModified }}$'
when: checkIfLineIsHere.changed
If the file contains "hello", the line will still contain "hello" and "hello, i love ansible" at the end.
If the file content doesn't contain "hello", the file is not modified.
You can use the file plugin for this scenario.
To set a fact you can use in other tasks ... this works.
- name: Check whether /tmp/my.conf contains "127.0.0.1"
set_fact:
myconf: "{{ lookup('file', '/tmp/my.conf') }}"
ignore_errors: yes
- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: "'127.0.0.1' in myconf"
To check the file content as a condition of a task ... this should work.
- name: Greet the world if /tmp/my.conf contains "127.0.0.1"
debug: msg="Hello, world!"
when: "'127.0.0.1' in lookup('file', '/tmp/my.conf')"
Another solution, also useful for other purposes is to loop over the contents of the file, line by line
- name: get the file
slurp:
src: /etc/locale.gen
register: slurped_file
- name: initialize the matches list
set_fact:
MATCHES: []
- name: collect matches in a list
set_fact:
MATCHES: "{{ MATCHES + [line2match] }}"
loop: "{{ file_lines }}"
loop_control:
loop_var: line2match
vars:
- decode_content: "{{ slurped_file.content | b64decode }}"
- file_lines: "{{ decode_content.split('\n') }}"
when: '"BE" in line2match'
- name: report matches if any
debug:
msg: "Found {{ MATCHES | length }} matches\n{{ MATCHES }}"
when: 'listlen | int > 0'
vars:
listlen: "{{ MATCHES | length }}"
This mechanism can be use to get a specific value from a matched line if you use it for example with the jinja regex_replace filter

ansible "with_lines: cat somefile" fails in a skipped block

I have a playbook with a block that has a when condition. Inside is a task with a loop. How can I change this loop so that when the condition is false the skipped task doesn't fail?
block:
- name: create a file
lineinfile:
line: "Hello World"
path: "{{my_testfile}}"
create: yes
- name: use the file
debug:
msg: "{{ item}}"
with_lines: cat "{{my_testfile}}"
when: false
TASK [create a file] ************************************************************************************************************************************************************
TASK [use the file] *************************************************************************************************************************************************************
cat: files/my/testfile: No such file or directory
fatal: [ipad-icpi01]: FAILED! => {"msg": "lookup_plugin.lines(cat \"files/mytestfile\") returned 1"}
Change your failing task to the following which will always be able to run, even if the file does not exists, and will not use the shell or command where there is no need to:
- name: use the file
debug:
msg: "{{ item }}"
loop: "{{ (lookup('file', my_testfile, errors='ignore') | default('', true)).split('\n') }}"
The key points:
use the file lookup plugin with errors='ignore' so that it returns the file content or None rather than an error when file does not exists.
use the default filter with second option to true so that it return default value if var exists but is null or empty.
split the result on new lines to get a list of lines (empty list if file does not exist).
Note: as reported by #Vladimir, I corrected your var name which is not valid in ansible.
Test the existence of the file. For example
- block:
- name: create a file
lineinfile:
line: "Hello World"
path: "{{ my_testfile }}"
create: yes
- name: use the file
shell: '[ -f "{{ my_testfile }}" ] && cat {{ my_testfile }}'
register: result
- name: use the file
debug:
msg: "{{ item }}"
loop: "{{ result.stdout_lines }}"
when: false
The lookup plugin file should be preferred.
I ended up with a mix of the provided answers. These tasks will be skipped without failing or creating a warning.
- block:
- name: create a file
lineinfile:
line: "Hello World"
path: "{{ my_testfile }}"
create: yes
- name: get the file
slurp:
src: "{{ my_testfile }}"
register: result
- name: use the file
debug:
msg: "{{ item }}"
loop: "{{ (result['content'] | b64decode).split('\n') }}"
when: false

using ansible variable in task conditonal

When I use an Ansible variable in the failed_when conditional, Ansible complains and fails by telling me that I cannot use Jinja2 expressions with failed_when.
Below snippet does not work:
vars:
var1: "var"
tasks:
- name: "sth"
raw: "anothersth"
register: status
failed_when: var1 in status.stdout
I want to use a regex in the above example and use variable var1 within a regex. This also fails.
I want to fail the task if var1 is repeated in the beginning and at the end of the stdout_lines. I was thinking something like this:
failed_when: regex("^{{var1}}/.*/{{var1}}$") in status.stdout
I wonder whether there is a way to achieve what I intend to do?
===============================================================
Exact play and the description:
Let me explain what I am trying to do:
run a command with "raw" module and register the stdout_lines.
iterate over a list of items, where list is a fact of current ansible host
use failed_when to search a pattern in the registered stdout and fail the task if it is not found
peers_underlay is a list defined in the host file:
peers_underlay:
- ip: "172.16.1.2"
- ip: "172.16.1.6"
This is the play:
- hosts: leaf-2, spine-1
gather_facts: no
tags: [ verify ]
vars:
bgp_underlay: "show ip bgp summary"
tasks:
- name: "underlay bgp test"
raw: "{{ bgp_underlay }}"
register: underlay_status
with_items: "{{ peers_underlay }}"
failed_when: not regex(".*/{{ item['ip'] }}/.*/Estab/.*") in underlay_status.stdout_lines
Q: "Fail the task if var1 is repeated in the beginning and at the end."
A: It's possible to test strings. For example, use regex
- hosts: localhost
vars:
my_stdout1: 'ABC dlkjfsldkfjsldkfj ABC'
my_stdout2: 'alkdjflaksdjflakdjflaksjdflaksdjflasj'
var1: 'ABC'
my_regex: '^{{ var1 }}(.*){{ var1 }}$'
tasks:
- debug:
msg: my_regex match my_stdout1
when: my_stdout1 is regex(my_regex)
- debug:
msg: my_regex match my_stdout2
when: my_stdout2 is regex(my_regex)
gives
"msg": "my_regex match my_stdout1"
The particular task sequence would be
vars:
var1: "var"
my_regex: '^{{ var1 }}(.*){{ var1 }}$'
tasks:
- name: "sth"
raw: "anothersth"
register: status
failed_when: status.stdout is regex(my_regex)

Need Syntax to add Ansible meta module to existing Playbook

I wish to search for a string ("AC245") in all files with extension *.db under /home/examples directory. Below is what i tried.
---
- name: "Find the details here "
hosts: localhost
any_errors_fatal: true
serial: 1
tasks:
- name: Ansible find files multiple patterns examples
find:
paths: /home/examples
patterns: "*.db"
recurse: yes
register: files_matched
- name: Search for String in the matched files
command: grep -i {{ myString }} {{ item.path }}
register: command_result
failed_when: command_result.rc == 0
with_items:
- "{{ files_matched.files }}"
run the above find.yml using this command:
ansible-playbook find.yml -e "myString=AC245"
My requirement is that if the string is found I wish to abort the play immediately using "meta: end_play" marking the playbook as FAILED.
Can you help suggest how can I update my current code to add the end_play feature as soon as the string is found in any *.db file ?
One possible solution is to move the task into a separate tasks file and loop over it. That will allow discrete control over each iteration of the task. For example:
playbook.yml:
---
- name: "Find the details here "
hosts: localhost
any_errors_fatal: true
serial: 1
tasks:
- name: Ansible find files multiple patterns examples
find:
paths: /home/mparkins/bin/playbooks_sandpit/outputs/dir
patterns: "*.db"
recurse: yes
register: files_matched
- name: Search for String in the matched files
include_tasks:
tasks.yml
with_items:
- "{{ files_matched.files }}"
tasks.yml:
- command: grep -i {{ myString }} {{ item.path }}
register: command_result
failed_when: command_result.rc == 0
You can add additional tasks in the tasks file if you wish to fail in a different way, for example using the fail module or meta: end_play
Q: "The requirement is that if the string is found I wish to abort the play immediately using "meta: end_play" marking the playbook as FAILED."
(ansible 2.7.9)
A: It's not possible.
1) It's not possible to execute meta: end_play in a loop on a condition (string is found)
2) It's not possible to execute both meta: end_play and fail/assert in one play
1) It is possible to write a filter_plugin (Python2)
$ cat filter_plugins/file_filters.py
import mmap
def file_list_search(list, string):
for file in list:
if file_search(file, string):
break
return file_search(file, string)
def file_search(file, string):
f = open(file)
s = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
if s.find(string) != -1:
return True
else:
return False
class FilterModule(object):
''' Ansible filters for operating on files '''
def filters(self):
return {
'file_search' : file_search,
'file_list_search' : file_list_search
}
and use it in a play. For example
- hosts: localhost
vars:
myString: "test string"
tasks:
- find:
paths: /home/examples
patterns: "*.db"
register: files_matched
- name: End of play when myString found
meta: end_play
when: "files_matched.files|
json_query('[*].path')|
file_list_search(myString)"
- debug:
msg: continue
2) It is possible to set_stats. The play below
- name: End of play when myString found
block:
- set_stats:
data:
FAILED: 1
- meta: end_play
when: "files_matched.files|
json_query('[*].path')|
file_list_search(myString)"
- debug:
msg: continue
- set_stats:
data:
FAILED: 0
gives the output below if the string is found
PLAY RECAP **********************************************************************************
127.0.0.1 : ok=4 changed=0 unreachable=0 failed=0
CUSTOM STATS: *******************************************************************************
RUN: { "FAILED": 1}
Allow show_custom_stats
$ grep stats ansible.cfg
show_custom_stats = True

Ansible: Insert line if not exists

I'm trying insert a line in a property file using ansible.
I want to add some property if it does not exist, but not replace it if such property already exists in the file.
I add to my ansible role
- name: add couchbase host to properties
lineinfile: dest=/database.properties regexp="^couchbase.host" line="couchbase.host=127.0.0.1"
But this replaces the property value back to 127.0.0.1 if it exists already in the file.
What I'm doing wrong?
The lineinfile module ensures the line as defined in line is present in the file and the line is identified by your regexp. So no matter what value your setting already has, it will be overridden by your new line.
If you don't want to override the line you first need to test the content and then apply that condition to the lineinfile module. There is no module for testing the content of a file so you probably need to run grep with a shell command and check the .stdout for content. Something like this (untested):
- name: Test for line
shell: grep -c "^couchbase.host" /database.properties || true
register: test_grep
And then apply the condition to your lineinfile task:
- name: add couchbase host to properties
lineinfile:
dest: /database.properties
line: couchbase.host=127.0.0.1
when: test_grep.stdout == "0"
The regexp then can be removed since you already made sure the line doesn't exist so it never would match.
But maybe you're doing things back to front. Where does that line in the file come from? When you manage your system with Ansible there should be no other mechanisms in place which interfere with the same config files. Maybe you can work around this by adding a default value to your role?
This is possible by simply using lineinfile and check_mode:
- name: Check if couchbase.host is already defined
lineinfile:
state: absent
path: "/database.properties"
regexp: "^couchbase.host="
check_mode: true
changed_when: false # This just makes things look prettier in the logs
register: check
- name: Define couchbase.host if undefined
lineinfile:
state: present
path: "/database.properties"
line: "couchbase.host=127.0.0.1"
when: check.found == 0
This is the only way I was able to get this to work.
- name: checking for host
shell: cat /database.properties | grep couchbase.host | wc -l
register: test_grep
- debug: msg="{{test_grep.stdout}}"
- name: adding license server
lineinfile: dest=/database.properties line="couchbase.host=127.0.0.1"
when: test_grep.stdout == "0"
By a long way of "Trials and errors" I come to this:
- name: check existence of line in the target file
command: grep -Fxq "ip addr add {{ item }}/32 dev lo label lo:{{ app | default('app') }}" /etc/rc.local
changed_when: false
failed_when: false
register: ip_test
with_items:
- "{{ list_of_ips }}"
- name: add autostart command
lineinfile: dest=/etc/rc.local
line="ip addr add {{ item.item }}/32 dev lo label lo:{{ app | default('app') }}"
insertbefore="exit 0"
state=present
when: item.rc == 1
with_items:
- "{{ ip_test.results }}"
Looks like it does not work if you use backrefs.
Following sample does not add a line
- name: add hosts file entry
lineinfile:
path: "/etc/hosts"
regexp: "foohost"
line: "10.10.10.10 foohost"
state: present
backrefs: yes
After removing backrefs I got my line added to the file
- name: add hosts file entry
lineinfile:
path: "/etc/hosts"
regexp: "foohost"
line: "10.10.10.10 foohost"
state: present
Same idea as presented here : https://stackoverflow.com/a/40890850/7231194
Steps are:
Try to replace the line.
If replace mod change it, restore
If replace mod doesn't change, add the line
Example
# Vars
- name: Set parameters
set_fact:
ipAddress : "127.0.0.1"
lineSearched : "couchbase.host={{ ipAddress }}"
lineModified : "couchbase.host={{ ipAddress }} hello"
# Tasks
- name: Try to replace the line
replace:
dest : /dir/file
replace : '{{ lineModified }} '
regexp : '{{ lineSearched }}$'
backup : yes
register : checkIfLineIsHere
# If the line not is here, I add it
- name: Add line
lineinfile:
state : present
dest : /dir/file
line : '{{ lineSearched }}'
regexp : ''
insertafter: EOF
when: checkIfLineIsHere.changed == false
# If the line is here, I still want this line in the file, Then restore it
- name: Restore the searched line.
lineinfile:
state : present
dest : /dir/file
line : '{{ lineSearched }}'
regexp : '{{ lineModified }}$'
when: checkIfLineIsHere.changed
Ok, here is mine naive solution... probably not a cross-platform and native Ansible (I've just started to use this tool and still learn it), but definitely shorter:
- name: Update /path/to/some/file
shell: grep -q 'regex' /path/to/some/file && echo exists || echo 'text-to-append' >> /path/to/some/file
register: result
changed_when: result.stdout.find('exists') == -1
We have tried the below and it worked well. our scenario need to entry "compress" in syslog file if it does not exist.
- name: Checking compress entry present if not add entry
lineinfile:
path: /etc/logrotate.d/syslog
regexp: " compress"
state: present
insertafter: " missingok"
line: " compress"
- name: add couchbase.host to properties, works like add or replace
lineinfile:
path: /database.properties
regexp: '^couchbase.host=(?!(127.0.0.1))\b'
line: 'couchbase.host=127.0.0.1'
This code will replace any line ^couchbase.host=* except couchbase.host=127.0.0.1 or will add new line if it does not exist
- name: add couchbase.host to properties, works like add or replace
lineinfile:
state: present
dest: /database.properties
regexp: '^couchbase.host'
line: 'couchbase.host=127.0.0.1'

Resources