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)时,如果有多行文本都匹配,这么这些行都会被删除。
- 如果没有匹配的行,则根据
insertbefore
或insertafter
参数的设置添加指定的行。 - 替换行时,必须确保正则表达式同时匹配修改前和被
line
替换后的行来保证语句的幂等性。
line 参数
:
- 指定的一行需要添加到文件中的文本。
- 替换行(state=present)时,必须指定该参数。
- 如果设置了
backrefs
参数,还包含向后引用。 - 别名:value。
backrefs 参数
:
- 替换行(state=present)时使用。
- 值为
yes
或no
,默认值no
。 - 如果指定了该参数,
insertafter
和insertbefore
参数会被忽略。 - 默认值为
no
,如果没有匹配,则添加一行line
。如果匹配了,则把匹配的内容替换为line
的内容。 - 值为
yes
时,表示开启后向引用,如果没有匹配,则文件保持不变。如果匹配了,把匹配内容替被换为line
的内容。
insertafter 参数
:
- 替换行(state=present)时使用。
- 值为
EOF
或者正则表达式,默认值为EOF
,表示End Of File
,插入到文件的末尾。 - 如果设置为正则表达式,默认将文本插入到正则表达式匹配的最后一行之后;如果指定了
firstmatch=yes
参数,则插入到匹配的第一行之后。 - 如果设置为正则表达式,但是没有匹配到任何行,则插入到文件末尾。
- 如果同时指定了
regexp
和insertafter
参数,仅当regexp
没有匹配成功时insertafter
参数才会生效。 - 当使用
backrefs
参数时,此参数会被忽略。
insertbefore 参数
:
- 替换行(state=present)时使用。
- 值为
BOF
或者正则表达式,默认值为BOF
,表示Begin Of File
,插入到文件的开头。 - 如果设置为正则表达式,默认将文本插入到正则表达式匹配的最后一行之前;如果指定了
firstmatch=yes
参数,则插入到匹配的第一行之前。 - 如果设置为正则表达式,但是没有匹配到任何行,则插入到文件开头。
- 如果同时指定了
regexp
和insertbefore
参数,仅当regexp
没有匹配成功时insertbefore
参数才会生效。 - 当使用
backrefs
参数时,此参数会被忽略。
firstmatch 参数
:
- 值为
yes
或no
,默认值no
。 - 和
insertafter
、insertbefore
参数一起使用。 - 值为
yes
时,表示insertafter
、insertbefore
参数使用正则表达式匹配的第一行而不是最后一行。
validate 参数
:
- 修改文件之前进行校验。
- 使用“%s”表示
path
参数指定的需要修改的文件。
file
模块的所有参数,常用的有:
backup
:是否在修改文件之前对文件进行备份。create
:yes
:当要操作的文件不存在时,创建对应的文件;默认为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 行替换语句了。