Issue
Please help me understand the more advanced syntax of sed. The way I understand it, I can use two sed commands in a single string to both search for pattern and then conditionally insert after that pattern. here is the goal. I have a file like this:
[PATTERN]
String
I need sed to insert "String" after [PATTERN] only if "String" doesn't exist.
"String" uses Ansible variables and basically looks like this:
{{ hostname.droplet.name }} ansible_ssh_host={{ hostname.droplet.ip_address }}
this translates to
hostname ansible_ssh_host=X.X.X.X
So ultimately I will have the following real world (non conceptual) example:
[DROPLETS]
ilovetacos ansible_ssh_host=127.0.0.1
If there is not a matching line below [DROPLETS] then append the line. If the particular hostname line already exists, then dont add the line again.
I can handle the first part:
sed '/\[DROPLETS\]/a STRING' inventory
Now here is my first problem. I dont know how to handle the ansible variables inside the sed command? Perhaps like this?
sed '/\[DROPLETS\]/a "{{ hostname.droplet.name }} ansible_ssh_host={{ hostname.droplet.ip_address }}"' inventory
The next part is to add the conditional check. I had considered just greping for the line first and then piping to sed, but it seems there is a better way to do all of this using a single sed command. Can someone please help me with this more advanced syntax?
Thanks
Solution
I still stand by my comment, that dependent on your use case, using dynamic inventory scripts is likely the way to go. However, if it is the case that the line you are looking to add can only ever exist at most once in the file this may meet your requirements:
(Credit to Konstantin Suvorov as this includes a technique taken from his website)
- name: Build inventory string
set_fact:
inventory_string: "{{ hostname.droplet.name }} ansible_ssh_host={{ hostname.droplet.ip_address }}"
inventory_file: /tmp/sssd.conf
- name: Add inventory string to inventory file if necessary
shell: |
grep "^{{ inventory_string }}" {{ inventory_file }} ||
sed -i '/\[DROPLETS\]/a {{ inventory_string }}' {{ inventory_file }}
register: output
changed_when: output.stdout != inventory_string
A few things going on in the shell
task:
- The
shell
command defines two commands, separated by||
. This a Unix shell construct that says the command that follows will only run if the command that precedes it fails. Then we usegrep
to see if the string already exists. Ifgrep
fails to find it, then thesed
command to add it is run - Without specifying a
changed_when
condition, the task will always report 'Changed'. Weregister
the output from the task. In the case thatgrep
finds your string, thestdout
will simply contain your string, so we can check for its existence to figure out whether thesed
command was triggered.
Answered By - clockworknet