# lineinfile problem

**URL:** <https://forum.ansible.com/t/lineinfile-problem/23561>\
**Category:** Ansible Project\
**Created:** [January 25, 2017, 10:37pm UTC](https://forum.ansible.com/t/lineinfile-problem/23561 "2017-01-25T22:37:38Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![mark.tovey](https://avatars.discourse-cdn.com/v4/letter/m/ce73a5/32.png) [@mark.tovey](https://forum.ansible.com/u/mark.tovey)\
**Post date:** [January 25, 2017, 10:37pm UTC](https://forum.ansible.com/t/lineinfile-problem/23561/1 "2017-01-25T22:37:38Z")

</div>

I have a problem where a line that contains a certain space delimited string must exist in a file. The string can be anywhere in the line: start, middle, or end. If a line that contains that string does not exist, then a line with that string needs to be inserted into the file. I have been trying to use the lineinfile module to solve this, but so far I have been unsuccessful. Below is the code I have tried:

- lineinfile:

dest: “/path/to/myfile”  
regexp: ‘^(._)(\s_this\_string\_must\_exist)(\s+.\*)$’  
line: ‘\g\<1\> this\_string\_must\_exist\g\<3\>’  
backrefs: true  
state: present

I have tried many variations of the regular expression and line, but nothing I have tried totally achieves what I am looking for. I have verified that the regular expression can locate a line with the string regardless of where the string is within the line, and if such a line is located it is not modified. But I have not been successful in getting a new line inserted if it does not already exist.  
Does anyone have any suggestions?  
-Mark

---

<div class="post-metadata">

**Author:** ![Kai\_Stian\_Olstad](https://avatars.discourse-cdn.com/v4/letter/k/e19adc/32.png) [@Kai\_Stian\_Olstad](https://forum.ansible.com/u/Kai_Stian_Olstad)\
**Post date:** [January 26, 2017, 6:42am UTC](https://forum.ansible.com/t/lineinfile-problem/23561/2 "2017-01-26T06:42:09Z")

</div>

The reason it doesn't work is explained in the documentation.

[https://docs.ansible.com/ansible/lineinfile\_module.html#options](https://docs.ansible.com/ansible/lineinfile_module.html#options)

In the comments about the backrefs:  
"... and if the regexp doesn't match anywhere in the file, the file will be left unchanged."

So you'll need to find a way to do it without backrefs: yes if you are going to use lineinfile.

---

<div class="post-metadata">

**Author:** ![mark.tovey](https://avatars.discourse-cdn.com/v4/letter/m/ce73a5/32.png) [@mark.tovey](https://forum.ansible.com/u/mark.tovey)\
**Post date:** [January 26, 2017, 3:44pm UTC](https://forum.ansible.com/t/lineinfile-problem/23561/3 "2017-01-26T15:44:47Z")

</div>

Yes, I finally spotted that immediately after I posted my initial query (when all else fails, read the documentation). Now I am trying to use lineinfile (or maybe grep) to look for the string and register the results, then use a second lineinfile to add a line if the results of the first lineinfile indicates that it is missing. This is a bit complicated because I have several strings that I need to look for and I want to use ‘with\_items’ to store them.  
-Mark

---

<div class="post-metadata">

**Author:** ![Jinesh\_Choksi](https://avatars.discourse-cdn.com/v4/letter/j/a6a055/32.png) [@Jinesh\_Choksi](https://forum.ansible.com/u/Jinesh_Choksi)\
**Post date:** [January 26, 2017, 3:59pm UTC](https://forum.ansible.com/t/lineinfile-problem/23561/4 "2017-01-26T15:59:33Z")

</div>

Hi Mark,

I found the following [https://relativkreativ.at/articles/how-to-use-ansibles-lineinfile-module-in-a-bulletproof-way](https://relativkreativ.at/articles/how-to-use-ansibles-lineinfile-module-in-a-bulletproof-way) very useful when I needed to find a reliable way to edit lines in a configuration file with Ansible tasks.

See if it helps you understand how to use lineinfile in a bulletproof way.

Regards,  
Jinesh

---

<div class="post-metadata">

**Author:** ![mark.tovey](https://avatars.discourse-cdn.com/v4/letter/m/ce73a5/32.png) [@mark.tovey](https://forum.ansible.com/u/mark.tovey)\
**Post date:** [January 26, 2017, 11:01pm UTC](https://forum.ansible.com/t/lineinfile-problem/23561/5 "2017-01-26T23:01:26Z")

</div>

Your article had interesting information, but it doesn’t look like it will help. I tried using negative look-ahead, but got nowhere with it.  
Now I am trying to use egrep to scan the file, and then use lineinfile to act upon the results. I put together the below snippet for testing:

- shell: chdir=~/tmp egrep “^._\s_{{item}}\s+.\*$” mytestfile  
register: result  
changed\_when: false  
failed\_when: false  
with\_items:

- “string2”

- “string6”

- “string7”

- debug: var={{item}}  
with\_items:

- result

This returns the following:

TASK [debug] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> (item=result) =\> {  
“item”: “result”,  
“result”: {  
“changed”: false,  
“msg”: “All items completed”,  
“results”: [  
{  
“\_ansible\_item\_result”: true,  
“\_ansible\_no\_log”: false,  
“\_ansible\_parsed”: true,  
“changed”: false,  
“cmd”: “egrep "^._\s_string2\s+._$" mytestfile",  
“delta”: “0:00:00.003006”,  
“end”: “2017-01-26 22:33:27.722164”,  
“failed”: false,  
“failed\_when\_result”: false,  
“invocation”: {  
“module\_args”: {  
“\_raw\_params”: "egrep "^._\s_string2\s+._$" mytestfile”,  
“\_uses\_shell”: true,  
“chdir”: “/home/pdxmft/tmp”,  
“creates”: null,  
“executable”: null,  
“removes”: null,  
“warn”: true  
},  
“module\_name”: “command”  
},  
“item”: “string2”,  
“rc”: 0,  
“start”: “2017-01-26 22:33:27.719158”,  
“stderr”: “”,  
“stdout”: “string1 string2 string3”,  
“stdout\_lines”: [  
“string1 string2 string3”  
],  
“warnings”:   
},  
{  
“\_ansible\_item\_result”: true,  
“\_ansible\_no\_log”: false,  
“\_ansible\_parsed”: true,  
“changed”: false,  
“cmd”: “egrep "^._\s_string6\s+._$" mytestfile",  
“delta”: “0:00:00.003093”,  
“end”: “2017-01-26 22:33:27.837867”,  
“failed”: false,  
“failed\_when\_result”: false,  
“invocation”: {  
“module\_args”: {  
“\_raw\_params”: "egrep "^._\s_string6\s+._$" mytestfile”,  
“\_uses\_shell”: true,  
“chdir”: “/home/pdxmft/tmp”,  
“creates”: null,  
“executable”: null,  
“removes”: null,  
“warn”: true  
},  
“module\_name”: “command”  
},  
“item”: “string6”,  
“rc”: 1,  
“start”: “2017-01-26 22:33:27.834774”,  
“stderr”: “”,  
“stdout”: “”,  
“stdout\_lines”: ,  
“warnings”:   
},  
{  
“\_ansible\_item\_result”: true,  
“\_ansible\_no\_log”: false,  
“\_ansible\_parsed”: true,  
“changed”: false,  
“cmd”: “egrep "^._\s_string7\s+._$" mytestfile",  
“delta”: “0:00:00.002986”,  
“end”: “2017-01-26 22:33:27.951455”,  
“failed”: false,  
“failed\_when\_result”: false,  
“invocation”: {  
“module\_args”: {  
“\_raw\_params”: "egrep "^._\s_string7\s+._$" mytestfile”,  
“\_uses\_shell”: true,  
“chdir”: “/home/pdxmft/tmp”,  
“creates”: null,  
“executable”: null,  
“removes”: null,  
“warn”: true  
},  
“module\_name”: “command”  
},  
“item”: “string7”,  
“rc”: 0,  
“start”: “2017-01-26 22:33:27.948469”,  
“stderr”: “”,  
“stdout”: “string7 string8 string9”,  
“stdout\_lines”: [  
“string7 string8 string9”  
],  
“warnings”:   
}  
]  
}  
}

What I would like to do now is walk through the results list and extract the “rc” and “item” values, something along the line of this:

- debug: var={{item.rc}}  
with\_items:
- result.results[\*]

But of course that does not work. So how can I walk through a list in this manner? I looked at ‘with\_subelements’ but was unable to put something together there.  
-Mark

---

<div class="post-metadata">

**Author:** ![Johannes\_Kastl](https://avatars.discourse-cdn.com/v4/letter/j/bbe5ce/32.png) [@Johannes\_Kastl](https://forum.ansible.com/u/Johannes_Kastl)\
**Post date:** [January 27, 2017, 7:44am UTC](https://forum.ansible.com/t/lineinfile-problem/23561/6 "2017-01-27T07:44:22Z")

</div>

First guess: Drop the "[\*]". Ansible knows this is a list and should  
use each element as "item".

Johannes

---

<div class="post-metadata">

**Author:** ![Jinesh\_Choksi](https://avatars.discourse-cdn.com/v4/letter/j/a6a055/32.png) [@Jinesh\_Choksi](https://forum.ansible.com/u/Jinesh_Choksi)\
**Post date:** [January 27, 2017, 11:25am UTC](https://forum.ansible.com/t/lineinfile-problem/23561/7 "2017-01-27T11:25:32Z")

</div>

**File: example\_file.txt**

`

string1 string2 string3  
string4 string5 string0  
string7 string8 string9

`

**File: run.sh**

`

#!/usr/bin/env bash  
ansible-playbook -vvv -i ‘localhost,’ -c local test.yml

`

**File: test.yml**

`

- hosts:

- localhost  
tasks:

- name: “Slurp the file we wish to search”  
slurp:  
src: ./example\_file.txt  
register: slurped\_file

- name: “To avoid base64 decoding multiple times, we do it once”  
set\_fact: plain\_file=“{{ slurped\_file[‘content’] | b64decode }}”

# - name: “You can use this task to test your regex”

# debug: msg=“{{ plain\_file | regex\_search(‘string7’) is none}}”

- name: “Insert the wanted line into the file as it doesn’t exist”  
lineinfile:  
dest: ./example\_file.txt  
line: “something {{ item }} somethingelse”  
state: present  
when: plain\_file | regex\_search(item) is none  
with\_items:
- string6
- string1
- string8
- foobar

`

Example output:

`

$ ./run.sh  
Using /etc/ansible/ansible.cfg as config file

PLAYBOOK: test.yml \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
1 plays in test.yml

PLAY [localhost] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

TASK [setup] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
Using module file /usr/lib/python2.7/site-packages/ansible/modules/core/system/setup.py  
 ESTABLISH LOCAL CONNECTION FOR USER: algomi-deploy  
 EXEC /bin/sh -c ‘( umask 77 && mkdir -p “`echo ~/.ansible/tmp/ansible-tmp-1485515755.89-254326766505950`” && echo ansible-tmp-1485515755.89-254326766505950=“`echo ~/.ansible/tmp/ansible-tmp-1485515755.89-254326766505950`” ) && sleep 0’  
 PUT /tmp/tmpP7Zu66 TO /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515755.89-254326766505950/setup.py  
 EXEC /bin/sh -c ‘chmod u+x /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515755.89-254326766505950/ /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515755.89-254326766505950/setup.py && sleep 0’  
 EXEC /bin/sh -c ‘/usr/bin/python /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515755.89-254326766505950/setup.py; rm -rf “/opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515755.89-254326766505950/” \> /dev/null 2\>&1 && sleep 0’  
ok: [localhost]

TASK [Slurp the file we wish to search] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
task path: /opt/home/algomi-deploy/test.yml:4  
Using module file /usr/lib/python2.7/site-packages/ansible/modules/core/network/basics/slurp.py  
 ESTABLISH LOCAL CONNECTION FOR USER: algomi-deploy  
 EXEC /bin/sh -c ‘( umask 77 && mkdir -p “`echo ~/.ansible/tmp/ansible-tmp-1485515756.18-190467128946445`” && echo ansible-tmp-1485515756.18-190467128946445=“`echo ~/.ansible/tmp/ansible-tmp-1485515756.18-190467128946445`” ) && sleep 0’  
 PUT /tmp/tmpUjpiaz TO /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.18-190467128946445/slurp.py  
 EXEC /bin/sh -c ‘chmod u+x /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.18-190467128946445/ /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.18-190467128946445/slurp.py && sleep 0’  
 EXEC /bin/sh -c ‘/usr/bin/python /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.18-190467128946445/slurp.py; rm -rf “/opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.18-190467128946445/” \> /dev/null 2\>&1 && sleep 0’  
ok: [localhost] =\> {  
“changed”: false,  
“content”: “c3RyaW5nMSBzdHJpbmcyIHN0cmluZzMKc3RyaW5nNCBzdHJpbmc1IHN0cmluZzAKc3RyaW5nNyBzdHJpbmc4IHN0cmluZzkK”,  
“encoding”: “base64”,  
“invocation”: {  
“module\_args”: {  
“src”: “./example\_file.txt”  
},  
“module\_name”: “slurp”  
},  
“source”: “./example\_file.txt”  
}

TASK [To avoid base64 decoding multiple times, we do it once] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
task path: /opt/home/algomi-deploy/test.yml:10  
ok: [localhost] =\> {  
“ansible\_facts”: {  
“plain\_file”: “string1 string2 string3\nstring4 string5 string0\nstring7 string8 string9\n”  
},  
“changed”: false,  
“invocation”: {  
“module\_args”: {  
“plain\_file”: “string1 string2 string3\nstring4 string5 string0\nstring7 string8 string9\n”  
},  
“module\_name”: “set\_fact”  
}  
}

TASK [Insert the wanted line into the file as it doesn’t exist] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
task path: /opt/home/algomi-deploy/test.yml:17  
Using module file /usr/lib/python2.7/site-packages/ansible/modules/core/files/lineinfile.py  
 ESTABLISH LOCAL CONNECTION FOR USER: algomi-deploy  
 EXEC /bin/sh -c ‘( umask 77 && mkdir -p “`echo ~/.ansible/tmp/ansible-tmp-1485515756.42-101048875702270`” && echo ansible-tmp-1485515756.42-101048875702270=“`echo ~/.ansible/tmp/ansible-tmp-1485515756.42-101048875702270`” ) && sleep 0’  
 PUT /tmp/tmpPv\_qtT TO /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.42-101048875702270/lineinfile.py  
 EXEC /bin/sh -c ‘chmod u+x /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.42-101048875702270/ /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.42-101048875702270/lineinfile.py && sleep 0’  
 EXEC /bin/sh -c ‘/usr/bin/python /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.42-101048875702270/lineinfile.py; rm -rf “/opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.42-101048875702270/” \> /dev/null 2\>&1 && sleep 0’  
changed: [localhost] =\> (item=string6) =\> {  
“backup”: “”,  
“changed”: true,  
“diff”: [  
{  
“after”: “”,  
“after\_header”: “./example\_file.txt (content)”,  
“before”: “”,  
“before\_header”: “./example\_file.txt (content)”  
},  
{  
“after\_header”: “./example\_file.txt (file attributes)”,  
“before\_header”: “./example\_file.txt (file attributes)”  
}  
],  
“invocation”: {  
“module\_args”: {  
“backrefs”: false,  
“backup”: false,  
“content”: null,  
“create”: false,  
“delimiter”: null,  
“dest”: “./example\_file.txt”,  
“directory\_mode”: null,  
“follow”: false,  
“force”: null,  
“group”: null,  
“insertafter”: null,  
“insertbefore”: null,  
“line”: “something string6 somethingelse”,  
“mode”: null,  
“owner”: null,  
“regexp”: null,  
“remote\_src”: null,  
“selevel”: null,  
“serole”: null,  
“setype”: null,  
“seuser”: null,  
“src”: null,  
“state”: “present”,  
“unsafe\_writes”: null,  
“validate”: null  
},  
“module\_name”: “lineinfile”  
},  
“item”: “string6”,  
“msg”: “line added”  
}  
skipping: [localhost] =\> (item=string1) =\> {  
“changed”: false,  
“item”: “string1”,  
“skip\_reason”: “Conditional check failed”,  
“skipped”: true  
}  
skipping: [localhost] =\> (item=string8) =\> {  
“changed”: false,  
“item”: “string8”,  
“skip\_reason”: “Conditional check failed”,  
“skipped”: true  
}  
Using module file /usr/lib/python2.7/site-packages/ansible/modules/core/files/lineinfile.py  
 EXEC /bin/sh -c ‘( umask 77 && mkdir -p “`echo ~/.ansible/tmp/ansible-tmp-1485515756.52-54649606538938`” && echo ansible-tmp-1485515756.52-54649606538938=“`echo ~/.ansible/tmp/ansible-tmp-1485515756.52-54649606538938`” ) && sleep 0’  
 PUT /tmp/tmpAvxVae TO /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.52-54649606538938/lineinfile.py  
 EXEC /bin/sh -c ‘chmod u+x /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.52-54649606538938/ /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.52-54649606538938/lineinfile.py && sleep 0’  
 EXEC /bin/sh -c ‘/usr/bin/python /opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.52-54649606538938/lineinfile.py; rm -rf “/opt/home/algomi-deploy/.ansible/tmp/ansible-tmp-1485515756.52-54649606538938/” \> /dev/null 2\>&1 && sleep 0’  
changed: [localhost] =\> (item=foobar) =\> {  
“backup”: “”,  
“changed”: true,  
“diff”: [  
{  
“after”: “”,  
“after\_header”: “./example\_file.txt (content)”,  
“before”: “”,  
“before\_header”: “./example\_file.txt (content)”  
},  
{  
“after\_header”: “./example\_file.txt (file attributes)”,  
“before\_header”: “./example\_file.txt (file attributes)”  
}  
],  
“invocation”: {  
“module\_args”: {  
“backrefs”: false,  
“backup”: false,  
“content”: null,  
“create”: false,  
“delimiter”: null,  
“dest”: “./example\_file.txt”,  
“directory\_mode”: null,  
“follow”: false,  
“force”: null,  
“group”: null,  
“insertafter”: null,  
“insertbefore”: null,  
“line”: “something foobar somethingelse”,  
“mode”: null,  
“owner”: null,  
“regexp”: null,  
“remote\_src”: null,  
“selevel”: null,  
“serole”: null,  
“setype”: null,  
“seuser”: null,  
“src”: null,  
“state”: “present”,  
“unsafe\_writes”: null,  
“validate”: null  
},  
“module\_name”: “lineinfile”  
},  
“item”: “foobar”,  
“msg”: “line added”  
}

PLAY RECAP \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
localhost : ok=4 changed=1 unreachable=0 failed=0

`

**Final contents of the example\_file.txt file:**

`

string1 string2 string3  
string4 string5 string0  
string7 string8 string9  
something string6 somethingelse  
something foobar somethingelse

`

- The above [slurps](http://docs.ansible.com/ansible/slurp_module.html) a file from the “remote” node.
- It converts the base64 encoded contents of the file into plain text so that we can regex search it
- It uses lineinfile to insert lines using with\_items when the regex\_search of the plain test file doesn’t match an item

The downsides of the above play are that the slurping a large file may not be possible for you due to memory restrictions. Also, you weren’t clear on what should be inserted into the file if the sought for string was not found and so the solution may not be complete.

Note: the regex\_search filter is something new (i.e. not in the [docs](http://docs.ansible.com/ansible/playbooks_filters.html#other-useful-filters) yet). I didn’t know about it until I came across this PR [adds two new regex filters for use in playbooks by privateip · Pull Request #14696 · ansible/ansible · GitHub](https://github.com/ansible/ansible/pull/14696)

I ran the above on ansible 2.2.1.0.

---

<div class="post-metadata">

**Author:** ![mark.tovey](https://avatars.discourse-cdn.com/v4/letter/m/ce73a5/32.png) [@mark.tovey](https://forum.ansible.com/u/mark.tovey)\
**Post date:** [January 30, 2017, 6:38pm UTC](https://forum.ansible.com/t/lineinfile-problem/23561/8 "2017-01-30T18:38:20Z")

</div>

I was not aware of the slurp module prior to this. That combined with the regex\_search filter certainly opens many avenues for searching files. I can see where this could be problematic for large files, but in this case that is not an issue. I am running Ansible version 2.2.0.0 and that appears to include the regex\_search filter. This solution works for me, so I will go with it.  
I looked around for more information about the regex\_search filter, but found very little. It is stored in the ansible/plugins/filter/core.py file if you want to look at it and see what other undocumented filters are available.  
-Mark
