一个专注于IT互联网运维的技术博客

Ansible单行替换模块lineinfile

2019.05.24

lineinfile 是 Ansible 的一个非常实用的模块,它可以使用 Python 的正则表达式确保一行特定的文本存在(state=present)或者不存在(state=absent)于指定的文件中。

1、lineinfile 模块的常用参数

path 参数

  • 必须指定的参数。
  • 和 file 模块的 path 参数一样,指定要操作的文件。
  • 别名:dest, destfile, name。

state 参数

  • 确保某一行存在(state=present,替换行)或者不存在(state=absent,删除行)。
  • 默认值为 present。

regexp 参数

  • 使用 Python 的正则表达式语法匹配文件中的每一行。
  • 替换行(state=present)时,如果有多行文本都匹配,只有最后面被匹配到的那行文本会被替换。
  • 删除行(state=absent)时,如果有多行文本都匹配,这么这些行都会被删除。
  • 如果没有匹配的行,则根据insertbeforeinsertafter参数的设置添加指定的行。
  • 替换行时,必须确保正则表达式同时匹配修改前和被line替换后的行来保证语句的幂等性。

line 参数

  • 指定的一行需要添加到文件中的文本。
  • 替换行(state=present)时,必须指定该参数。
  • 如果设置了backrefs参数,还包含向后引用。
  • 别名:value。

backrefs 参数

  • 替换行(state=present)时使用。
  • 值为yesno,默认值no
  • 如果指定了该参数,insertafterinsertbefore参数会被忽略。
  • 默认值为no,如果没有匹配,则添加一行line。如果匹配了,则把匹配的内容替换为line的内容。
  • 值为yes时,表示开启后向引用,如果没有匹配,则文件保持不变。如果匹配了,把匹配内容替被换为line的内容。

insertafter 参数

  • 替换行(state=present)时使用。
  • 值为EOF或者正则表达式,默认值为EOF,表示End Of File,插入到文件的末尾。
  • 如果设置为正则表达式,默认将文本插入到正则表达式匹配的最后一行之后;如果指定了firstmatch=yes参数,则插入到匹配的第一行之后。
  • 如果设置为正则表达式,但是没有匹配到任何行,则插入到文件末尾。
  • 如果同时指定了regexpinsertafter参数,仅当regexp没有匹配成功时insertafter参数才会生效。
  • 当使用backrefs参数时,此参数会被忽略。

insertbefore 参数

  • 替换行(state=present)时使用。
  • 值为BOF或者正则表达式,默认值为BOF,表示Begin Of File,插入到文件的开头。
  • 如果设置为正则表达式,默认将文本插入到正则表达式匹配的最后一行之前;如果指定了firstmatch=yes参数,则插入到匹配的第一行之前。
  • 如果设置为正则表达式,但是没有匹配到任何行,则插入到文件开头。
  • 如果同时指定了regexpinsertbefore参数,仅当regexp没有匹配成功时insertbefore参数才会生效。
  • 当使用backrefs参数时,此参数会被忽略。

firstmatch 参数

  • 值为yesno,默认值no
  • insertafterinsertbefore参数一起使用。
  • 值为yes时,表示insertafterinsertbefore参数使用正则表达式匹配的第一行而不是最后一行。

validate 参数

  • 修改文件之前进行校验。
  • 使用“%s”表示path参数指定的需要修改的文件。

file模块的所有参数,常用的有:

  • backup:是否在修改文件之前对文件进行备份。
  • createyes:当要操作的文件不存在时,创建对应的文件;默认为no:当要操作的文件不存在时,语句报错。
  • mode:文件的属性。
  • owner:文件的属主。
  • group:文件的属组。

2、lineinfile 模块使用示例

参考lineinfile – Manage lines in text files

1、确保 SELinux 设置为 enforcing 状态。SELinux 配置文件为/etc/selinux/config,将正则表达式^SELINUX=匹配的最后一行修改为SELINUX=enforcing

- name: Ensure SELinux is set to enforcing mode
  lineinfile:
    path: /etc/selinux/config
    regexp: '^SELINUX='
    line: SELINUX=enforcing

2、确保 sudoers 配置文件中不存在用户组 wheel。sudoers 配置文件为/etc/sudoers,删除该文件中匹配正则表达式^%wheel的所有行:

- name: Make sure group wheel is not in the sudoers configuration
  lineinfile:
    path: /etc/sudoers
    state: absent
    regexp: '^%wheel'

3、将 hosts 文件/etc/hosts中正则表达式^127\.0\.0\.1匹配的最后一行修改为127.0.0.1 localhost,同时修改文件属主和属组为root,属性为0644

- name: Replace a localhost entry with our own
  lineinfile:
    path: /etc/hosts
    regexp: '^127\.0\.0\.1'
    line: 127.0.0.1 localhost
    owner: root
    group: root
    mode: '0644'

4、修改默认 Apache 的监听端口为 8080。Apache 的配置文件/etc/httpd/conf/httpd.conf,将正则表达式^Listen匹配的最后一行修改为Listen 8080;如果没有匹配的行,在正则表达式^#Listen匹配的最后一行之后添加Listen 8080;如果还是没有匹配的行,直接在文件末尾添加Listen 8080

- name: Ensure the default Apache port is 8080
  lineinfile:
    path: /etc/httpd/conf/httpd.conf
    regexp: '^Listen '
    insertafter: '^#Listen '
    line: Listen 8080

5、在/etc/services文件中添加自定义描述。修改/etc/services文件中正则表达式^# port for http匹配的最后一行为# port for http by default;如果没有匹配的行,在正则表达式^www.*80/tcp匹配的最后一行之前添加# port for http by default;如果还是没有匹配的行,直接在文件开头添加# port for http by default

- name: Ensure we have our own comment added to /etc/services
  lineinfile:
    path: /etc/services
    regexp: '^# port for http'
    insertbefore: '^www.*80/tcp'
    line: '# port for http by default'

6、确保文件/tmp/testfile中存在行192.168.1.99 foo.lab.net foo且仅有一行,如果文件不存在则自动创建:

- name: Add a line to a file if the file does not exist, without passing regexp
  lineinfile:
    path: /tmp/testfile
    line: 192.168.1.99 foo.lab.net foo
    create: yes

7、精确设置 JBoss 的内存。假设 ${xms} 值为 2000,则如下的示例将替换-Xmx3550m -Xms3550m -Xmn2g -Xss128k-Xmx3550m -Xms2000m -Xmn2g -Xss128k

# NOTE: Yaml requires escaping backslashes in double quotes but not in single quotes
- name: Ensure the JBoss memory settings are exactly as needed
  lineinfile:
    path: /opt/jboss-as/bin/standalone.conf
    regexp: '^(.*)Xms(\\d+)m(.*)$'
    line: '\1Xms${xms}m\3'
    backrefs: yes
  • 这里backrefs = yes,如果没有匹配成功,则不会修改/opt/jboss-as/bin/standalone.conf文件内容。

8、设置用户组 ADMIN 无需密码即可使用sudo命令,并且使用/usr/sbin/visudo -cf /etc/sudoers命令校验配置文件:

# NOTE: Fully quoted because of the ': ' on the line. See the Gotchas in the YAML docs.
- name: Validate the sudoers file before saving
  lineinfile:
    path: /etc/sudoers
    state: present
    regexp: '^%ADMIN ALL='
    line: '%ADMIN ALL=(ALL) NOPASSWD: ALL'
    validate: /usr/sbin/visudo -cf %s

学会了上面几个常用的参数之后,就可以使用 lineinfile 模块编写更复杂的 Ansible 行替换语句了。

发表评论