Ansible - 使用 ansible.builtin.replace 模块替换文件中两行指定行之间的所有文本

Ansible - Replace all text between two specified lines in file with ansible.builtin.replace module

提问人:Eschin Tenebrous 提问时间:10/27/2023 更新时间:10/27/2023 访问量:77

问:

我一直在尝试使用 Ansible 替换配置文件中两行指定行之间的所有文本。

使用此任务块,我只想删除两个指定行之间的所有文本。在下一个任务中,我将在这两行之间添加新配置。

感谢任何指导/帮助,谢谢!

      - name: Remove all lines between specified lines in hosts file.
        ansible.builtin.replace:
          path: /etc/hosts
          after: "^#BeginEntries$"
          before: "^#EndEntries$"
          regexp: '.*'
          replace: ""
          backup: yes

当前的任务块似乎与我的之后/之前不匹配。即使指定文件中确实存在这两行,也不会进行任何更改。

正则表达式 文本 替换 Ansible

评论

0赞 Darin 10/27/2023
我不熟悉 Ansible,但我确实得到了一个正则表达式来工作在这个 Regex101 中。在左栏中有一个“FLAVOR”部分,如果您知道 Ansible 中使用了哪种风格的正则表达式,那么您可以在那里更改它并进行实验,直到某些东西起作用。\n
1赞 Eschin Tenebrous 10/27/2023
谢谢!安德鲁下面的回答似乎也表明了这一点。使用可能就是诀窍。不过,我喜欢 blockinfile 提出的解决方案,所以会先尝试一下,如果它按预期工作,就会运行它 =)\n

答:

1赞 Andrew 10/27/2023 #1

如果你的最终目标是替换这些行之间的内容,你应该使用 ansible.builtin.blockinfile 模块并立即替换它!看:state: present

文本.txt

123
#BeginEntries
bad_entry_1
bad_entry_2
#EndEntries
321

playbook.yaml

- name: Replace block
  hosts: localhost
  tasks:
    - name: Replace block
      ansible.builtin.blockinfile:
        path: "{{ playbook_dir }}/text.txt"
        marker: "#{mark}"
        marker_begin: "BeginEntries"
        marker_end: "EndEntries"
        state: present
        content: |
          my awsome content with

          even

          multiple

          blank

          lines

输出:

❯ ansible-playbook playbook.yaml -i localhost,

PLAY [Replace block] *************************************************************************************************************************

TASK [Gathering Facts] ***********************************************************************************************************************
ok: [localhost]

TASK [Replace block] *************************************************************************************************************************
changed: [localhost]

PLAY RECAP ***********************************************************************************************************************************
localhost                  : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

❯ cat text.txt
123
#BeginEntries
my awsome content with

even

multiple

blank

lines
#EndEntries
321

在上面的示例中,我们将标记本身(开始 #)定义为 BeginEntries 和 EndEntries 作为开始和结束块。没有必要使用正则表达式,因为在这种情况下 - 匹配是准确的。

如果你真的希望这是一个 2 步操作(删除然后修改),你也可以使用这个模块,但需要注意的是,你最终会在标记之间得到空字符串(根据文档,空的“内容”或“块”会导致state: absent)

- name: Remove block
  hosts: localhost
  tasks:
    - name: Remove block
      ansible.builtin.blockinfile:
        path: "{{ playbook_dir }}/text.txt"
        marker: "#{mark}"
        marker_begin: "BeginEntries"
        marker_end: "EndEntries"
        state: present
        content: "{{ '\n' }}"

然后 text.txt 的输出将是

❯ cat text.txt
123
321
#BeginEntries

#EndEntries

关于替换模块的示例,似乎“^”和“$”标记在替换模块的参数之前和之后的多行模式下不起作用,这可能是您没有得到预期结果的原因。您可以使用换行符来解决此行为,如下所示:

      ansible.builtin.replace:
        path: "{{ playbook_dir }}/text.txt"
        after: "\n#BeginEntries\n"
        before: "\n#EndEntries\n"
        regexp: '.*'
        replace: ""

这将导致

123
#BeginEntries


#EndEntries
321

但我仍然强烈建议使用 blockinfile 模块,因为它基本上是为您的用例制作的。

评论

0赞 Eschin Tenebrous 10/27/2023
谢谢!我将在接下来的一两天内使用 blockinfile 对此进行测试,并以任何一种方式报告 =)
0赞 Eschin Tenebrous 10/27/2023
blockinfile 绝对是要走的路。让它按预期工作:)我也能够根据您的建议进行替换工作,但替换似乎不一致。在一次传球中,它实际上也爆炸了。在另一次传递中,它在之后/之前之间添加了多个替换字符串,而不仅仅是一个......替换模块的结果奇怪且不一致,但它确实经常起作用。感谢您的帮助!肯定:)使用 blockinfile#EndEntries