Theppasin Kongsakda
Theppasin Kongsakda

Reputation: 207

Ansible - Insert line if not exists and don't insert if line exists that separate by spaces

I use lineinfile module to insert a line that doesn't exists but when it's exists with multiple space, it still insert a line.

Input:

one two three

Expect:

(not exists)     < Insert
one two three    < Don't insert (it's correct)
one  two  three  < Don't insert (having same words but multiple spaces)

My code:

- lineinfile: 
    path: /somefile
    line: 'one two three'

My output:

Before : one  two  three
After  : one  two  three
         one two three

Upvotes: 0

Views: 2951

Answers (1)

Vladimir Botka
Vladimir Botka

Reputation: 67959

Q: "Expect"

1. (not exists)     < Insert
2. one two three    < Don't insert (it's correct)
3. one  two  three  < Don't insert (having same words but multiple spaces)

A: It's not possible to fulfill all the expectations in single run of the module lineinfile. It's possible to use backrefs and preserve the spacing (case 3.). But new lines won't be inserted (case 1.). Without backrefs new lines will be added, but the spacing of existing lines won't be preserved (case 2.).

No backrefs

The task below does the job. In particular, regexp matches any sequences in front, among, and after the words

    - lineinfile:
        path: test.txt
        regexp: '^(.*){{ item.0 }}(.*){{ item.1 }}(.*){{ item.2 }}(.*)$'
        line: '{{ item.0 }} {{ item.1 }} {{ item.2 }}'
      loop:
        - ['one','two','three']
        - ['four','five','six']

Given the file test.txt

shell> cat test.txt
one    two      three

the playbook with this task gives

shell> ansible-playbook pb.yml

shell> cat test.txt
one two three
four five six

As a next example, the regexp below gives the same result and restricts the sequence to whitespace only. At least one space must be among the words.

    - lineinfile:
        path: test.txt
        regexp: '^(\s*){{ item.0 }}(\s+){{ item.1 }}(\s+){{ item.2 }}(\s*)$'
        line: '{{ item.0 }} {{ item.1 }} {{ item.2 }}'
      loop:
        - ['one','two','three']
        - ['four','five','six']

Backrefs

It's possible to preserve the spacing of the existing lines. See backrefs. But, lines that do not exist won't be added.

    - lineinfile:
        backrefs: true
        path: test.txt
        regexp: '^(.*){{ item.0 }}(.*){{ item.1 }}(.*){{ item.2 }}(.*)$'
        line: '{{ item.0 }}\2{{ item.1 }}\3{{ item.2 }}'
      loop:
        - ['one','two','three']
        - ['four','five','six']

For example, given the same file

shell> cat test.txt
one    two      three

the playbook with this task skips both iterations and changes nothing

shell> ansible-playbook pb.yml

shell> cat test.txt
one    two      three

Upvotes: 1

Related Questions