'lineinfile on all matches

Since lineinfile only check the first or last match, is there a way I can use it to edit my file as I wanted on all matches?

Example : I have a file like the one below and I want to add ZZZ after all AAA matches.

Source file:

AAA
BBB
AAA
CCC
DDD

Desired output :

AAA
ZZZ
BBB
AAA
ZZZ
CCC
DDD

I tried the module replace, but since it has to match a regex, I don't really know how I can write it either.



Solution 1:[1]

write your task:

  tasks:
    - name: replace
      replace:
        path: ./pathoffile
        regexp: '^(AAA)$'
        replace: '\1\nZZZ'

or if you dont want to use group regex

    regexp: '^AAA$'
    replace: 'AAA\nZZZ'

use regex: '^(AAA)$(?!\nZZZ)' if you want to change only AAA not followed by \nZZZ

Solution 2:[2]

The solution below works, but it's not idempotent. The backreference '\1\nZZZ' will make no difference

    - replace:
        path: test.txt
        regexp: '^AAA$'
        replace: 'AAA\nZZZ'

Running the play in check and diff mode --check --diff you can see the newline \nZZZ will be added repeatedly

TASK [replace] ********************************************
--- before: test.txt
+++ after: test.txt
@@ -1,7 +1,9 @@
 AAA
+ZZZ
 ZZZ
 BBB
 AAA
 ZZZ
+ZZZ
 CCC
 DDD

Use Python regex negative lookahead assertion (?!...) to make the task idempotent. The regexp below will match only if AAA\n is not followed by ZZZ

    - replace:
        path: test.txt
        regexp: 'AAA\n(?!ZZZ)'
        replace: 'AAA\nZZZ\n'

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2