Home > Net >  Insert lines in a file from an other file lines in Ansible
Insert lines in a file from an other file lines in Ansible

Time:08-12

I would copy lines from a file /tmp/test1 to a file /tmp/test2 the /tmp/test1 contains:

argument1
argument2
@test1
@test2
@test3

the /tmp/test2 contains:

argument1.1
argument2192
@example
@test2
@example1

So my main goal is to insert every line that doesn't exist in /tmp/test2 from file /tmp/test1 and that the line added must be added at the end of the last line which is containing the same begin of line: ^[[:alpha:]] and ^@, so /tmp/test2 should look like this:

argument1.1
argument2192
argument1
argument2
@example
@test2
@example1
@test1
@test3

I created this playbook but it doesn't do what i am looking for:

                  - name: check test1 content
                    command: cat /tmp/test1
                    register: tmp_content


                  - name: insert line
                    lineinfile:
                      path: /tmp/test2
                      line: '{{item}}'
                      insertafter: "^@*"
                    loop: "{{tmp_content.stdout_lines}}"

CodePudding user response:

1) "Insert every line that doesn't exist in /tmp/test2 from file /tmp/test1"

2) "The line added must be added at the end of the last line which is containing the same beginning."

A: The task below does the job. If the first character is @ the line is inserted at the end of the file. Otherwise, the line is inserted before the first line starting with @. The parameters insertafter and insertbefore may not be used together. The negative options omit make the parameters insertafter and insertbefore mutually exclusive

    - name: insert line
      lineinfile:
        path: /tmp/test2
        line: "{{ item }}"
        insertafter: "{{ (item.0 == '@')|ternary('EOF', omit) }}"
        insertbefore: "{{ (item.0 != '@')|ternary('^@.*$', omit) }}"
        firstmatch: true
      loop: "{{ tmp_content.stdout_lines }}"

Notes

  • Example of a complete playbook for testing
shell> cat pb.yml
- hosts: localhost
  tasks:
    - name: check test1 content
      command: cat /tmp/test1
      register: tmp_content
      changed_when: false
    - name: insert line
      lineinfile:
        path: /tmp/test2
        line: "{{ item }}"
        insertafter: "{{ (item.0 == '@')|ternary('EOF', omit) }}"
        insertbefore: "{{ (item.0 != '@')|ternary('^@.*$', omit)}}"
        firstmatch: true
      loop: "{{ tmp_content.stdout_lines }}"

The playbook is idempotent. See the output of the diff_mode below

shell> ansible-playbook pb.yml --diff

...

TASK [insert line] *************************************************
--- before: /tmp/test2 (content)
    after: /tmp/test2 (content)
@@ -1,5  1,6 @@
 argument1.1
 argument2192
 argument1
 @example
 @test2
 @example1

changed: [localhost] => (item=argument1)
--- before: /tmp/test2 (content)
    after: /tmp/test2 (content)
@@ -1,6  1,7 @@
 argument1.1
 argument2192
 argument1
 argument2
 @example
 @test2
 @example1

changed: [localhost] => (item=argument2)
--- before: /tmp/test2 (content)
    after: /tmp/test2 (content)
@@ -5,3  5,4 @@
 @example
 @test2
 @example1
 @test1

changed: [localhost] => (item=@test1)
ok: [localhost] => (item=@test2)
--- before: /tmp/test2 (content)
    after: /tmp/test2 (content)
@@ -6,3  6,4 @@
 @test2
 @example1
 @test1
 @test3

changed: [localhost] => (item=@test3)

  • Brute force option

Read the files

    - command: cat /tmp/test1
      register: test1
    - command: cat /tmp/test2
      register: test2

Declare the variables

l1_alpha: "{{ test1.stdout_lines|select('match', '^[^@].*$') }}"
l1_glyph: "{{ test1.stdout_lines|select('match', '^@.*$') }}"
l2_alpha: "{{ test2.stdout_lines|select('match', '^[^@].*$') }}"
l2_glyph: "{{ test2.stdout_lines|select('match', '^@.*$') }}"
l1_alpha_diff: "{{ l1_alpha|difference(l2_alpha) }}"
l1_glyph_diff: "{{ l1_glyph|difference(l2_glyph) }}"
result: "{{ l2_alpha   l1_alpha_diff   l2_glyph   l1_glyph_diff }}"

This gives the expected result

    - debug:
        msg: |
          {% for line in result %}
          {{ line }}
          {% endfor %}
  msg: |-
    argument1.1
    argument2192
    argument1
    argument2
    @example
    @test2
    @example1
    @test1
    @test3

Write it to a file

    - copy:
        dest: /tmp/test2
        content: |
          {% for line in result %}
          {{ line }}
          {% endfor %}

gives

shell> cat /tmp/test2
argument1.1
argument2192
argument1
argument2
@example
@test2
@example1
@test1
@test3

Example of a complete playbook for testing

shell> cat pb.yml
- hosts: localhost

  vars:
    l1_alpha: "{{ test1.stdout_lines|select('match', '^[^@].*$') }}"
    l1_glyph: "{{ test1.stdout_lines|select('match', '^@.*$') }}"
    l2_alpha: "{{ test2.stdout_lines|select('match', '^[^@].*$') }}"
    l2_glyph: "{{ test2.stdout_lines|select('match', '^@.*$') }}"
    l1_alpha_diff: "{{ l1_alpha|difference(l2_alpha) }}"
    l1_glyph_diff: "{{ l1_glyph|difference(l2_glyph) }}"
    result: "{{ l2_alpha   l1_alpha_diff   l2_glyph   l1_glyph_diff }}"
    
  tasks:
    - command: cat /tmp/test1
      register: test1
      changed_when: false
    - command: cat /tmp/test2
      register: test2
      changed_when: false
    - copy:
        dest: /tmp/test2
        content: |
          {% for line in result %}
          {{ line }}
          {% endfor %}

The playbook is idempotent.

  • Related