ansible.builtin.replace 模块 – 使用反向引用正则表达式替换文件中的所有特定字符串实例

注意

此模块是 ansible-core 的一部分,包含在所有 Ansible 安装中。在大多数情况下,您甚至可以在不指定 collections 关键字 的情况下使用简短模块名称 replace。但是,我们建议您使用 完全限定的集合名称 (FQCN) ansible.builtin.replace 以便轻松链接到模块文档并避免与可能具有相同模块名称的其他集合发生冲突。

概要

  • 此模块将替换文件中模式的所有实例。

  • 由用户负责通过确保相同的模式永远不会匹配任何进行的替换来维护幂等性。

参数

参数

评论

after

字符串

如果指定,则只会替换/删除此匹配之后的內容。

可以与 before 结合使用。

使用 Python 正则表达式;请参阅 https://docs.pythonlang.cn/3/library/re.html

使用 DOTALL,这意味着 . 特殊字符 *可以匹配换行符*。

不使用 MULTILINE,因此 ^$ 将只匹配文件的开头和结尾。

attributes

别名:attr

字符串

生成的 filesystem 对象应具有的属性。

要获取支持的标志,请查看目标系统上 chattr 的手册页。

此字符串应包含与 lsattr 显示的顺序相同的属性。

假设 = 运算符为默认值,否则需要在字符串中包含 +- 运算符。

backup

布尔值

创建一个包含时间戳信息的备份文件,以便您可以在错误地覆盖文件后找回原始文件。

选择

  • false ← (默认)

  • true

before

字符串

如果指定,则只会替换/删除此匹配之前的內容。

可以与 after 结合使用。

使用 Python 正则表达式;请参阅 https://docs.pythonlang.cn/3/library/re.html

使用 DOTALL,这意味着 . 特殊字符 *可以匹配换行符*。

不使用 MULTILINE,因此 ^$ 将只匹配文件的开头和结尾。

encoding

字符串

用于读取和写入文件的字符编码。

默认值: "utf-8"

group

字符串

应拥有 filesystem 对象的组的名称,如将提供给 chown

当未指定时,它使用当前用户的当前组,除非您是 root 用户,在这种情况下,它可以保留之前的拥有权。

mode

任何

生成的 filesystem 对象应具有的权限。

对于习惯于 /usr/bin/chmod 的人来说,请记住模式实际上是八进制数。您必须向 Ansible 提供足够的資訊来正确解析它们。为了获得一致的结果,请引用八进制数(例如,'644''1777'),以便 Ansible 接收到一个字符串并可以将其从字符串转换为数字。在某些情况下,添加一个前导零(例如,0755)有时会有效,但可能会在循环和其他一些情况下失败。

如果您向 Ansible 提供一个数字,但没有遵循这些规则中的任何一个,那么最终将得到一个十进制数,这将导致意外结果。

从 Ansible 1.8 开始,模式可以指定为符号模式(例如,u+rwxu=rw,g=r,o=r)。

如果未指定 mode 并且目标 filesystem 对象 *不存在*,则在设置新创建的 filesystem 对象的模式时,将使用系统上的默认 umask

如果未指定 mode 并且目标 filesystem 对象 *存在*,则将使用现有 filesystem 对象的模式。

指定 mode 是确保以正确的权限创建 filesystem 对象的最佳方式。有关更多详细信息,请参阅 CVE-2020-1736。

owner

字符串

应拥有 filesystem 对象的用户的名称,如将提供给 chown

当未指定时,它使用当前用户,除非您是 root 用户,在这种情况下,它可以保留之前的拥有权。

指定数字用户名将被视为用户 ID,而不是用户名。避免使用数字用户名以避免此混乱。

path

别名:dest、destfile、name

路径 / 必需

要修改的文件。

在 Ansible 2.3 之前,此选项只能用作 destdestfilename

regexp

字符串 / 必需

要在文件内容中查找的正则表达式。

使用 Python 正则表达式;请参阅 https://docs.pythonlang.cn/3/library/re.html

使用 MULTILINE 模式,这意味着 ^$ 匹配文件的开头和结尾,以及文件 *每一行* 的开头和结尾。

不使用 DOTALL,这意味着 . 特殊字符匹配 *除换行符以外的任何字符*。一个常见的错误是假设否定字符集(如 [^#])也不会匹配换行符。

为了排除换行符,必须将它们添加到集中,例如 [^#\n]

请注意,从 Ansible 2.0 开始,简短形式的任务应在其任何转义序列之前添加反斜杠,以防止将它们解析为字符串文字转义。请参阅示例。

replace

字符串

用于替换 regexp 匹配项的字符串。

可能包含反向引用,如果 regexp 匹配,这些引用将使用 regexp 捕获组扩展。

如果未设置,则完全删除匹配项。

反向引用可以像 \1 一样模棱两可地使用,也可以像 \g<1> 一样显式地使用。

默认值: ""

selevel

字符串

SELinux filesystem 对象上下文的 level 部分。

这是 MLS/MCS 属性,有时称为 range

当设置为 _default 时,它将使用策略的 level 部分(如果可用)。

serole

字符串

SELinux filesystem 对象上下文的 role 部分。

当设置为 _default 时,它将使用策略的 role 部分(如果可用)。

setype

字符串

SELinux filesystem 对象上下文的 type 部分。

当设置为 _default 时,它将使用策略的 type 部分(如果可用)。

seuser

字符串

SELinux filesystem 对象上下文的 user 部分。

默认情况下,它使用system策略(如果适用)。

当设置为_default时,它将使用策略的user部分(如果可用)。

unsafe_writes

布尔值

影响何时使用原子操作以防止目标文件系统对象的数据损坏或不一致读取。

默认情况下,此模块使用原子操作来防止目标文件系统对象的数据损坏或不一致读取,但有时系统会以阻止此操作的方式进行配置或出现故障。一个例子是 Docker 挂载的文件系统对象,它们无法从容器内部以原子方式更新,只能以不安全的方式写入。

此选项允许 Ansible 在原子操作失败时回退到不安全的文件系统对象更新方法(但是,它不会强制 Ansible 执行不安全的写入)。

重要提示!不安全的写入会受到竞争条件的影响,并可能导致数据损坏。

选择

  • false ← (默认)

  • true

validate

字符串

在将更新后的文件复制到最终目的地之前要运行的验证命令。

使用临时文件路径进行验证,通过%s传递,该路径必须存在,如以下示例所示。

此外,命令以安全方式传递,因此 shell 功能(如扩展和管道)将不起作用。

有关如何处理比此选项提供的更复杂的验证的示例,请参阅处理复杂验证

属性

属性

支持

描述

check_mode

支持:完全支持

可以在 check_mode 下运行并返回更改状态预测,而无需修改目标。如果不支持,则将跳过操作。

diff_mode

支持:完全支持

在 diff 模式下,将返回有关已更改内容(或可能需要在 check_mode 下更改的内容)的详细信息。

platform

平台: posix

可以对其进行操作的目标操作系统/系列。

safe_file_operations

支持:完全支持

使用 Ansible 的严格文件操作函数来确保正确的权限并避免数据损坏。

vault

支持:不支持

可以自动解密 Ansible 加密的 vault 文件。

备注

注意

  • 从 Ansible 2.3 开始,dest选项已更改为path作为默认选项,但dest仍然有效。

  • 从 Ansible 2.7.10 开始,beforeafter的组合使用可以正常工作。如果您依赖于以前的错误行为,您可能需要调整您的任务。有关详细信息,请参阅https://github.com/ansible/ansible/issues/31354

  • 选项follow已在 Ansible 2.5 中删除,因为此模块修改了文件的内容,因此follow=no没有意义。

示例

- name: Replace old hostname with new hostname (requires Ansible >= 2.4)
  ansible.builtin.replace:
    path: /etc/hosts
    regexp: '(\s+)old\.host\.name(\s+.*)?$'
    replace: '\1new.host.name\2'

- name: Replace after the expression till the end of the file (requires Ansible >= 2.4)
  ansible.builtin.replace:
    path: /etc/apache2/sites-available/default.conf
    after: 'NameVirtualHost [*]'
    regexp: '^(.+)$'
    replace: '# \1'

- name: Replace before the expression from the beginning of the file (requires Ansible >= 2.4)
  ansible.builtin.replace:
    path: /etc/apache2/sites-available/default.conf
    before: '# live site config'
    regexp: '^(.+)$'
    replace: '# \1'

# Prior to Ansible 2.7.10, using before and after in combination did the opposite of what was intended.
# see https://github.com/ansible/ansible/issues/31354 for details.
# Note (?m) which turns on MULTILINE mode so ^ matches any line's beginning
- name: Replace between the expressions (requires Ansible >= 2.4)
  ansible.builtin.replace:
    path: /etc/hosts
    after: '(?m)^<VirtualHost [*]>'
    before: '</VirtualHost>'
    regexp: '^(.+)$'
    replace: '# \1'

- name: Supports common file attributes
  ansible.builtin.replace:
    path: /home/jdoe/.ssh/known_hosts
    regexp: '^old\.host\.name[^\n]*\n'
    owner: jdoe
    group: jdoe
    mode: '0644'

- name: Supports a validate command
  ansible.builtin.replace:
    path: /etc/apache/ports
    regexp: '^(NameVirtualHost|Listen)\s+80\s*$'
    replace: '\1 127.0.0.1:8080'
    validate: '/usr/sbin/apache2ctl -f %s -t'

- name: Short form task (in ansible 2+) necessitates backslash-escaped sequences
  ansible.builtin.replace: path=/etc/hosts regexp='\\b(localhost)(\\d*)\\b' replace='\\1\\2.localdomain\\2 \\1\\2'

- name: Long form task does not
  ansible.builtin.replace:
    path: /etc/hosts
    regexp: '\b(localhost)(\d*)\b'
    replace: '\1\2.localdomain\2 \1\2'

- name: Explicitly specifying positional matched groups in replacement
  ansible.builtin.replace:
    path: /etc/ssh/sshd_config
    regexp: '^(ListenAddress[ ]+)[^\n]+$'
    replace: '\g<1>0.0.0.0'

- name: Explicitly specifying named matched groups
  ansible.builtin.replace:
    path: /etc/ssh/sshd_config
    regexp: '^(?P<dctv>ListenAddress[ ]+)(?P<host>[^\n]+)$'
    replace: '#\g<dctv>\g<host>\n\g<dctv>0.0.0.0'

作者

  • Evan Kaufman (@EvanK)