虚拟化容器,大数据,DBA,中间件,监控。

Ansible 常用模块之文件内容修改 blockinfile|lineinfile

20 12月
作者:admin|分类:系统运维

前文中,我们已经介绍了怎样使用模块,而且我们知道,ansible有很多模块,每个模块都有自己的功能,"模块"涉及到的方向比较多,所以对于个人来说,并没有必要了解所有的模块,我们只需要根据实际的业务场景了解相应的模块即可,而且ansible比较贴心,ansible根据模块的功能对这些模块进行了大致的分类,比如,如果某些模块都是操作文件的,就把它们分类到文件类模块中,如果某些模块都是操作数据库的,就把他们分类到数据库类模块中,那么,ansible把模块分为了哪些类呢?你可以参考官方手册。

上述链接不仅对模块进行了分类,还给出了每个模块的使用示例,不过这些示例都是编写"剧本(playbook)"的示例,我们还没有介绍过怎样编写剧本,所以暂时不会参考这些示例,前文的示例中,我们一直以命令的方式运行ansible,通过命令的方式调用模块,这种直接在命令行中运行的ansible命令被称作为"ad-hoc命令",我们可以通过"ad-hoc命令"的方式,快速的了解一个模块。

在前文的示例中,我们已经了解了ping模块与fetch模块,那么这篇文章中,我们来了解一些新的模块,这些模块都是常用的操作文件的模块,不过这篇文章写得并不全面,后续有空会继续补充总结,对等更新的朋友说声见谅,最近比较忙。

 

blockinfile模块 


blockinfile模块可以帮助我们在指定的文件中插入"一段文本",这段文本是被标记过的,换句话说就是,我们在这段文本上做了记号,以便在以后的操作中可以通过"标记"找到这段文本,然后修改或者删除它,单单这样描述不是特别容易理解,结合下面的小例子动手做做立马就能够明白了。

此处我们介绍一些blockinfile模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。

  • path参数 :必须参数,指定要操作的文件。
  • block参数 :此参数用于指定我们想要操作的那"一段文本",此参数有一个别名叫"content",使用content或block的作用是相同的。
  • marker参数 :假如我们想要在指定文件中插入一段文本,ansible会自动为这段文本添加两个标记,一个开始标记,一个结束标记,默认情况下,开始标记为# BEGIN ANSIBLE MANAGED BLOCK,结束标记为# END ANSIBLE MANAGED BLOCK,我们可以使用marker参数自定义"标记",比如,marker=#{mark}test ,这样设置以后,开始标记变成了# BEGIN test,结束标记变成了# END test,没错,{mark}会自动被替换成开始标记和结束标记中的BEGIN和END,我们也可以插入很多段文本,为不同的段落添加不同的标记,下次通过对应的标记即可找到对应的段落。
  • state参数 : state参数有两个可选值,present与absent,默认情况下,我们会将指定的一段文本"插入"到文件中,如果对应的文件中已经存在对应标记的文本,默认会更新对应段落,在执行插入操作或更新操作时,state的值为present,默认值就是present,如果对应的文件中已经存在对应标记的文本并且将state的值设置为absent,则表示从文件中删除对应标记的段落。
  • insertafter参数 :在插入一段文本时,默认会在文件的末尾插入文本,如果你想要将文本插入在某一行的后面,可以使用此参数指定对应的行,也可以使用正则表达式(python正则),表示将文本插入在符合正则表达式的行的后面,如果有多行文本都能够匹配对应的正则表达式,则以最后一个满足正则的行为准,此参数的值还可以设置为EOF,表示将文本插入到文档末尾。
  • insertbefore参数 :在插入一段文本时,默认会在文件的末尾插入文本,如果你想要将文本插入在某一行的前面,可以使用此参数指定对应的行,也可以使用正则表达式(python正则),表示将文本插入在符合正则表达式的行的前面,如果有多行文本都能够匹配对应的正则表达式,则以最后一个满足正则的行为准,此参数的值还可以设置为BOF,表示将文本插入到文档开头。
  • backup参数 :是否在修改文件之前对文件进行备份。
  • create参数 :当要操作的文件并不存在时,是否创建对应的文件。

 

对应上述参数的ad-hoc示例命令如下:

为了方便举例,我们将/etc/rc.d/rc.local文件复制到/testdir目录中,以做测试

假如,我们想要在test70主机中的/testdir/rc.local文件尾部插入如下两行:

systemctl start mariadb
systemctl start httpd

可以使用如下命令

ansible test70 -m blockinfile -a 'path=/testdir/rc.local block="systemctl start mariadb\nsystemctl start httpd" '

使用path参数指定要操作的文件,使用block参数指定文本块内容,由于我们使用了ad-hoc命令,所以我们使用\n表示换行,在写ansible剧本时则可以直接将文本块写在多行中,但是我们还没有介绍剧本的编写,所以此处不用在意,当执行上述命令后,/testdir/rc.local的文件尾部会多出如下文本块:

# BEGIN ANSIBLE MANAGED BLOCK
systemctl start mariadb
systemctl start httpd
# END ANSIBLE MANAGED BLOCK

正如之前所说,blockinfile模块的作用就是在文件中添加、更新、或者删除"被标记的文本块",而上述被标记的文本块就是我们添加进文件的,# BEGIN ANSIBLE MANAGED BLOCK 和 # END ANSIBLE MANAGED BLOCK 就是blockinfile模块自动为我们添加的文本块标记,一个是开始标记,一个是结束标记。

 

我们也可以自定义标记,但是自定义的标记仍然要"成对出现",需要有开始标记和结束标记,示例如下:

ansible test70 -m blockinfile -a 'path=/testdir/rc.local block="systemctl start mariadb\nsystemctl start httpd" marker="#{mark} serivce to start" '

使用marker可以自定义文本块的标记, 上例中的"{mark}" 会自动被替换成开始标记中的"BEGIN" 和结束标记中的 "END",如果文件中不存在同名标记的文本块,那么文件的末尾将会出现如下文本块。

#BEGIN serivce to start
systemctl start mariadb
systemctl start httpd
#END serivce to start

在执行完上述命令的基础上,执行如下命令

ansible test70 -m blockinfile -a 'path=/testdir/rc.local block="systemctl start mariadb" marker="#{mark} serivce to start" '

因为在执行此命令时,"#{mark} serivce to start"标记对应的文本块已经存在于文件中,而同时,block参数对应的内容又与之前文本块的内容不同,所以,这种情况下,对应文本块中的内容会被更新,而不会再一次插入新的文本块,这种用法相当于更新原来文本块中的内容,执行上述命令后,文本块的内容被更新为如下文本。

#BEGIN serivce to start
systemctl start mariadb
#END serivce to start

在执行完上述命令的基础上,执行如下命令

ansible test70 -m blockinfile -a 'path=/testdir/rc.local block="" marker="#{mark} serivce to start" '

因为在执行此命令时,"#{mark} serivce to start"标记对应的文本块已经存在于文件中,而同时,block参数对应的内容为空,这时,blockinfile模块会删除对应标记的文本块,我们还可以使用如下命令删除对应的文本块,它们的效果是相同的。

ansible test70 -m blockinfile -a 'path=/testdir/rc.local marker="#{mark} serivce to start" state=absent'

 默认情况下,文本块插入在文件的尾部,我们也可以将文本块插入指定的位置,比如,插入在文件开头,或者根据正则表达式去匹配对应的行,然后将文本块插入到匹配到的行的前头或者后头,示例如下

如果想要将文本块插入到文档的开头,可以使用insertbefore参数,将其值设置为BOF,BOF表示Begin Of File

ansible test70 -m blockinfile -a 'path=/testdir/rc.local block="####blockinfile test####"  marker="#{mark} test" insertbefore=BOF'

如果使用如下命令,表示将文本块插入到文档的结尾,与默认操作相同,将insertafter参数设置为EOF表示End Of File

ansible test70 -m blockinfile -a 'path=/testdir/rc.local block="####blockinfile test####"  marker="#{mark} test" insertafter=EOF'

使用如下命令表示使用正则表达式匹配行,将文本块插入到 "以#!/bin/bash开头的行" 之后

ansible test70 -m blockinfile -a 'path=/testdir/rc.local block="####blockinfile test####"  marker="#{mark} test reg" insertafter="^#!/bin/bash" '

使用backup参数,可以在操作修改文件之前,对文件进行备份,备份的文件会在原文件名的基础上添加时间戳

ansible test70 -m blockinfile -a 'path=/testdir/rc.local marker="#{mark} test" state=absent backup=yes'

使用create参数,如果指定的文件不存在,则创建它,示例如下:

ansible test70 -m blockinfile -a 'path=/testdir/test block="test" marker="#{mark} test" create=yes'

 

lineinfile模块


我们可以借助lineinfile模块,确保"某一行文本"存在于指定的文件中,或者确保从文件中删除指定的"文本"(即确保指定的文本不存在于文件中),还可以根据正则表达式,替换"某一行文本"。 

此处我们介绍一些lineinfile模块的常用参数,你可以先对这些参数有一个大概了解,然后再看小示例。

path参数 :必须参数,指定要操作的文件。

line参数 :  使用此参数指定文本内容。

regexp参数 :使用正则表达式匹配对应的行,当替换文本时,如果有多行文本都能被匹配,则只有最后面被匹配到的那行文本才会被替换,当删除文本时,如果有多行文本都能被匹配,这么这些行都会被删除。

state参数:当想要删除对应的文本时,需要将state参数的值设置为absent,absent为缺席之意,表示删除,state的默认值为present

backrefs参数:默认情况下,当根据正则替换文本时,即使regexp参数中的正则存在分组,在line参数中也不能对正则中的分组进行引用,除非将backrefs参数的值设置为yes,backrefs=yes表示开启后向引用,这样,line参数中就能对regexp参数中的分组进行后向引用了,这样说不太容易明白,参考下面的示例命令比较直观一点,backrefs=yes除了能够开启后向引用功能,还有另一个作用,默认情况下,当使用正则表达式替换对应行时,如果正则没有匹配到任何的行,那么line对应的内容会被插入到文本的末尾,不过,如果使用了backrefs=yes,情况就不一样了,当使用正则表达式替换对应行时,同时设置了backrefs=yes,那么当正则没有匹配到任何的行时,则不会对文件进行任何操作,相当于保持原文件不变,如果没有理解,就按照下面的示例命令,动手操作一下吧,那样更加直观。

insertafter参数:借助insertafter参数可以将文本插入到“指定的行”之后,insertafter参数的值可以设置为EOF或者正则表达式,EOF为End Of File之意,表示插入到文档的末尾,默认情况下insertafter的值为EOF,如果将insertafter的值设置为正则表达式,表示将文本插入到匹配到正则的行之后,如果正则没有匹配到任何行,则插入到文件末尾,当使用backrefs参数时,此参数会被忽略。

insertbefore参数:借助insertbefore参数可以将文本插入到“指定的行”之前,insertbefore参数的值可以设置为BOF或者正则表达式,BOF为Begin Of File之意,表示插入到文档的开头,如果将insertbefore的值设置为正则表达式,表示将文本插入到匹配到正则的行之前,如果正则没有匹配到任何行,则插入到文件末尾,当使用backrefs参数时,此参数会被忽略。

backup参数:是否在修改文件之前对文件进行备份。

create参数 :当要操作的文件并不存在时,是否创建对应的文件。

对应上述参数的ad-hoc示例命令如下:

为了方便举例,我们使用/testdir/test文件作为被操作的文件,test文件内容如下

# cat /testdir/test
Hello ansible,Hiiii
lineinfile -
Ensure a particular line is in a file,
lineinfile -
or replace an existing line using a back-referenced regular expression.

确保指定的"一行文本"存在于文件中,如果指定的文本本来就存在于文件中,则不做任何操作,如果不存在,默认在文件的末尾插入这行文本,如下命令表示确保"test lineinfile"这行文本存在于/testdir/test文件中。

ansible test70 -m lineinfile -a 'path=/testdir/test line="test text"'

如下命令表示根据正则表达式替换"某一行",如果不止一行能够匹配正则,那么只有最后一个匹配正则的行才会被替换,被匹配行会被替换成line参数指定的内容,但是如果指定的表达式没有匹配到任何一行,那么line中的内容会被添加到文件的最后一行。

ansible test70 -m lineinfile -a 'path=/testdir/test regexp="^line" line="test text" '

如下命令表示根据正则表达式替换"某一行",如果不止一行能够匹配正则,那么只有最后一个匹配正则的行才会被替换,被匹配行会被替换成line参数指定的内容,但是如果指定的表达式没有匹配到任何一行,那么则不对文件进行任何操作。

ansible test70 -m lineinfile -a 'path=/testdir/test regexp="^line" line="test text" backrefs=yes '

根据line参数的内容删除行,如果文件中有多行都与line参数的内容相同,那么这些相同的行都会被删除。

ansible test70 -m lineinfile -a 'path=/testdir/test line="lineinfile -" state=absent'

根据正则表达式删除对应行,如果有多行都满足正则表达式,那么所有匹配的行都会被删除

ansible test70 -m lineinfile -a 'path=/testdir/test regexp="^lineinfile" state=absent'

 默认情况下,lineinfile模块不支持后向引用(如果对后向引用不是特别了解,可以参考本站中的另一片文章 Linux正则之分组与后向引用

如果将backrefs设置为yes,表示开启支持后向引用,使用如下命令,可以将test示例文件中的"Hello ansible,Hiiii"替换成"Hiiii",如果不设置backrefs=yes,则不支持后向引用,那么"Hello ansible,Hiiii"将被替换成"\2"

浏览406 评论0
返回
目录
返回
首页
Ansible 常用模块之文件操作查找与内容替换 find|replace Ansible 导入剧本(import_playbook)和导入任务(import_tasks)