Ansible lineinfile examples - Add, Modify, Delete, Replace lines

Ansible lineinfile module could be the saviour of your day when you want to work with files and especially modify their content on the run, like adding a new line in the file or updating a line in the file or replace a line in the file when certain text is found and much more.

lineinfile has a various set of examples and it provides many parameters to get your job done easily. In this post, we are going to see the ansible lineinfile module in action with examples.

ansible lineinfile examples

The Ansible lineinfile module

Ansible lineinfile module is helpful when you want to add, remove, modify a single line in a file.  You can also use conditions to match the line before modifying or removing using the regular expressions. You can reuse and modify the matched line using the back reference parameter.

Consider yourself having any of these following requirement

  1. Add a line when it is not already present.
  2. Change the port number in the configuration file
  3. Disable the SSL when the SSL is enabled
  4. Add a new entry in the /etc/hosts file
  5. Upgrade the package version when the installed version is matching your regular expression
  6. Remove a username from /etc/passwd file using regex

Hope this sets the context. Before we proceed with the examples Something to be highlighted.

Ansible Lineinfile can be used only for working a single line in a file. If you want to replace mutiple lines try replace module or use blockinfile if you want to insert/update/remove a block of lines in a file.

If you want to explore more about the Ansible Replace module you can refer this post.

Ansible replace line in file – Ansible Replace Examples | Devops Junction

 

Ansible lineinfile examples

We have gathered various examples of ansible lineinfile here.  These are examples we have covered in this post. you can choose to read all or any specific example.

  • Validate if a line is present without any modification
  • Validate if a line is present in the file and add if it does not exist
  • Replace a Line in a file If it is found with ansible lineinfile
  • Remove a line from the file if it is found - All the instances
  • Insert before a matching line using insertbefore parameter
  • Insert after the matching line using insertafter parameter
  • validate the changes are correct before saving

 

Example 1: Validate if a line is present in the file without any modification

This is just to validate if a line is present in the file or not. It will not modify the file irrespective of whatsoever the result is. this is just like running the quick find command

The Example given below is to find whether or not the String "LogLevel debug" is found in the remote apache web server's httpd.conf file.

As mentioned earlier. There would be no action taken whatsoever

In this example we are going to check if the LogLevel is Debug and print the message If it is there or not and take no action. This is being done with the help of checkmode=yes

---
  - name: Examples of lineinfile
    hosts: web
    
    tasks:
      - name: "Example1: Validate if a String or line is present in the file"
        become: yes
        become_user: root
        tags: example1
        lineinfile:
          path: /etc/httpd/conf/httpd.conf
          line: "LogLevel debug"
          state: present
          backup: yes
        check_mode: yes
        register: example1out

Though this playbook would report that there is a change made by marking it as changed=1 but this would not do any modification on the file as we ran the task in Check mode.

Here is the Quick ad-hoc command to check what is the actual LogLevel in the remote httpd.conf file

$ ansible web -m shell -a "grep -i LogLevel /etc/httpd/conf/httpd.conf" -i ansible_hosts
mwiweb02 | CHANGED | rc=0 >>
# LogLevel: Control the number of messages logged to the error_log.
LogLevel warn

 It is recommended to always have the backup: yes parameter in your playbook when you are using the lineinfile. This would make sure the file is backed up before any changes are made. This would help in case if you want to roll back.

 

Example2: Validate if a String or line is present in the file and add if it does not exist

In the same playbook, we have just seen if we remove the check mode it would be a valid playbook which searches  for a line and adds it when there are no matches found

But there is a problem here the line you are mentioning to be added would be added only at the End Of File or Last line. This can be controlled with insert_before and insert_before directives which will be discussed later in this article.

Now the playbook

---
  - name: Examples of lineinfile
    hosts: web
    
    tasks:
      - name: "Example2: Add the line if it does not exist"
        become: yes
        become_user: root
        tags: example2
        lineinfile:
          path: /etc/httpd/conf/httpd.conf
          line: "LogLevel debug"
          state: present
          backup: yes
        register: example2out

The result of this would result in a invalid configuration file as the entry would be added at the End Of File.

$ ansible web -m shell -a "grep -in LogLevel /etc/httpd/conf/httpd.conf" 
mwiweb02 | CHANGED | rc=0 >>
185:# LogLevel: Control the number of messages logged to the error_log.
189:LogLevel warn
354:LogLevel debug

Which can be controlled with Insert after and insert before which we will later in this post.

Example3: Replace a line in a file with ansible lineinfile.

In the example2 we have seen how to add a new line with lineinfile module. Now we are going to see how to replace a line when a Certain line is found.

Though you can use the ansible replace module to replace. The Lineinfile module can also be used to replace a line.

Now in this example, we are going to change the LogLevel debug to LogLevel Debug with a capital D

We are going to use the Ansible Lineinfile with  Regular Expressions  to Search for a line and the line element would contain the line argument would hold the line to replace with

Look at the following Playbook and you can easily understand it.

---
  - name: Examples of lineinfile
    hosts: web
    
    tasks:
      - name: "Example1: Validate if a String or line is present in the file"
        become: yes
        become_user: root
        tags: example1
        lineinfile:
          path: /etc/httpd/conf/httpd.conf
          # The String to Search
          regexp: "LogLevel warn" 
          # The String to Replace
          line: "LogLevel debug"
          state: present
          backup: yes
        
        register: example1out

The Result of the file would be something like this

$ ansible web -m shell -a "grep -in LogLevel /etc/httpd/conf/httpd.conf" -i ansible_hosts
mwiweb02 | CHANGED | rc=0 >>
185:# LogLevel: Control the number of messages logged to the error_log.
189:LogLevel debug

 

Would it Replace all the Matching Lines? What if there are More than one Matches

If there are more than one matches in the file. Ansible Lineinfile would replace only the last line matched or found.

If you would like to replace all the occurrences,  you must consider using the replace module and not lineinfile.

 

Example 4: Remove a line from the file,  if it is found ( All the Instances )

Now I want to remove the Line  LogLevel Debug which we have added earlier as it is in the wrong place and also we already have theLogLevel warn present in the same file.

Here is the ansible playbook to remove the Line from the file and we can use some Regular expressions here to find both debug and Debug

---
  - name: Examples of lineinfile
    hosts: web
    
    tasks:
      - name: "Example1: Validate if a String or line is present in the file"
        become: yes
        become_user: root
        tags: example1
        lineinfile:
          path: /etc/httpd/conf/httpd.conf
          # String to Search
          regexp: "LogLevel [Dd]ebug" 
          # State is set to Absent to remove if the Searching Line is found
          state: absent
          backup: yes
        
        register: example1out

Here we are setting the state parameter as absent which will remove if the Search is Success. the line parameter is not used as it is not necessary

As mentioned earlier, this would remove all the matching lines from the file, in other words, all the appearance of a Search Line.

Example5: Insert After a matching line using insertafter parameter

Since we have taken Apache httpd.conf file as our base file in this post, Let us take some requirement  we used to do often in Apache, which is adding a new listener

First Let us see what is there in the file already

$ ansible web -m shell -a "grep -in Listen /etc/httpd/conf/httpd.conf" -i ansible_hosts
mwiweb02 | CHANGED | rc=0 >>
34:# Listen: Allows you to bind Apache to specific IP addresses and/or
38:# Change this to Listen on specific IP addresses as shown below to 
41:#Listen 12.34.56.78:80
42:Listen 80

here 42 is the line number and you can see that we have only one Listen statement/directive as of now. Now in order to make Apache Listen to 443 we need to add Listen 443 right beneath the Listen 80 
Let us see how to Insert after some line using insertafter parameter.

Here is the playbook.

---
  - name: Examples of lineinfile
    hosts: web
    
    tasks:
      - name: "Example1: Validate if a String or line is present in the file"
        become: yes
        become_user: root
        tags: lineinfileexample
        lineinfile:
          path: /etc/httpd/conf/httpd.conf
          insertafter: "^Listen [0-9]+" 
          line: "Listen 443"
          firstmatch: yes
          state: present  
        register: lineinfileexample

Here you can notice that there is no REGEX parameter.  we do not need this as the insertafter parameter itself can have the Search String with the Regular Expression Syntax

 

$ ansible web -m shell -a "grep -in Listen /etc/httpd/conf/httpd.conf" -i ansible_hosts
mwiweb02 | CHANGED | rc=0 >>
34:# Listen: Allows you to bind Apache to specific IP addresses and/or
38:# Change this to Listen on specific IP addresses as shown below to 
41:#Listen 12.34.56.78:80
42:Listen 80
43:Listen 443

If you notice the Line numbers in the Output,  You can see the Listen 443 has been added right beneath the Listen 80

When there are multiple entries of the searching line is present in the file. The last matched line would be considered.

Example6: Insert Before a matching line using insertbefore parameter

To Test the insert before parameter,  Let us take the same httpd.conf file as a base file and this time we are going to update the ServerAdmin Email ID from the default  ServerAdmin root@localhost to Server Admin [email protected]

Before any modification

aksarav@middlewareinventory:/apps/vagrant/webinfra$ ansible web -m shell -a "grep -in ServerAdmin /etc/httpd/conf/httpd.conf" -i ansible_hosts
mwiweb02 | CHANGED | rc=0 >>
83:# ServerAdmin: Your address, where problems with the server should be
87:ServerAdmin root@localhost

But we need to Disable/Comment the Existing ServerAdmin line and add a new entry, Here is the playbook to do both these tasks.

---
  - name: Examples of lineinfile
    hosts: web
    
    tasks:
      - name: "Example6: Comment the Exisiting ServerAdmin Line"
        become: yes
        become_user: root
        tags: lineinfileexample6_1
        lineinfile:
          path: /etc/httpd/conf/httpd.conf
          regexp: '(^ServerAdmin .*)'
          line: '# \1'
          backrefs: yes
          state: present
        register: lineinfileexample6_1

      - name: "Example6: Add a New ServerAdmin Before the Commented Line"
        become: yes
        become_user: root
        tags: lineinfileexample6_2
        lineinfile:
          path: /etc/httpd/conf/httpd.conf
          insertbefore: '# ServerAdmin .*'
          line: "ServerAdmin [email protected]"
          state: present  
        register: lineinfileexample6_2

The Expected result would be something like follows.

aksarav@middlewareinventory:/apps/vagrant/webinfra$ ansible web -m shell -a "grep -in ServerAdmin /etc/httpd/conf/httpd.conf" -i ansible_hosts
mwiweb02 | CHANGED | rc=0 >>
83:# ServerAdmin: Your address, where problems with the server should be
87:ServerAdmin aksarav@middlewareinventory.com
88:# ServerAdmin root@localhost

You can see the Line Number 88 is commented now, it was the older Server Admin and line number 87 is our new ServerAdmin

 

Example 7:   Validate the Changes Before Saving/Committing

This is a Nice feature of Ansible lineinfile which will let you run a shell command to validate if the modified file is really OK or if there are any issues. Since our base file is a configuration file httpd.conf it has some syntax and If we miss adhering to it, we will leave the entire website/infra at stake.

So let us validate it before saving the file.

Apache HTTPD server has a command to perform the Syntax check on the httpd.conf file which is httpd -t

When invoked and with no syntax issues. It would print the message Syntax OK like given below and return a Zero Return Code which is all it matters to Ansible. Ansible relies on the Validation Command's Return Code.

[aksarav@mwiweb02 ~]$ httpd -t 
Syntax OK

If it is NON-ZERO the Changes would not be committed and the task will fail.

Here is the playbook to Update the ServerName Directive of Apache.

---
  - name: Examples of lineinfile
    hosts: web
    tasks:
      - name: "Example7: Update the ServerName"
        become: yes
        become_user: root
        lineinfile:
          path: /etc/httpd/conf/httpd.conf
          insertafter: '#ServerName www.example.com:80'
          line: "ServerName www.middlewareinventory.com:80"
          state: present  
          # Command to Validate the Configuration and %s is a working copy of the file
          validate: "httpd -t -f %s"

Here the %s is the working copy of the actual file. Ansible would always copy the file and keep it as a working copy and make the changes and finally copy it over to the Destined location and replace the original file.

Quick Ad Hoc command to validate

$ ansible web -m shell -a "grep -in ServerName /etc/httpd/conf/httpd.conf" -i ansible_hosts
mwiweb02 | CHANGED | rc=0 >>
92:# ServerName gives the name and port that the server uses to identify itself.
98:#ServerName www.example.com:80
99:ServerName www.middlewareinventory.com:80 

You can see the ServerName directive has been added.

We have come to the End of the Article.

Hope it helps

Rate this article [ratings]

Cheers
Sarav AK

Follow me on Linkedin My Profile
Follow DevopsJunction onFacebook orTwitter
For more practical videos and tutorials. Subscribe to our channel

Buy Me a Coffee at ko-fi.com

Signup for Exclusive "Subscriber-only" Content

Loading