Shell高手必备:30字搞定XML注释过滤
引子
我们知道,使用shell进行行级处理,很easy!例如grep、sed、awk这些命令都是处理文本的超级工具。好用到爆。
但是对于结构体文本怎么处理呢?举个例子:
我们要查tomcat-users.xml 中的用户是否是默认用户,配置的密码是否足够复杂。首先,我们肯定要把注释掉的内容过滤掉,不然检查的结果就不准确了。
cat tomcat-users.xml
<!--
The sample user and role entries below are intended for use with the
examples web application. They are wrapped in a comment and thus are ignored
when reading this file. If you wish to configure these users for use with the
examples web application, do not forget to remove the <!.. ..> that surrounds
them. You will also need to set the passwords to something appropriate.
-->
<!--
<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="<must-be-changed>" roles="tomcat"/>
<user username="both" password="<must-be-changed>" roles="tomcat,role1"/>
<user username="role1" password="<must-be-changed>" roles="role1"/>
-->
</tomcat-users>
再比如,查看日志的轮转规则,如何去判定全局的rotate和局部配置块内的rotate?总不能看谁前面有空格,谁没有吧?按道理全局的前面也可以加空格的,只是不好看而已。
cat /etc/logrotate.conf
weekly
rotate 24
/var/log/wtmp {
missingok
monthly
create 0664 root utmp
minsize 1M
rotate 6
}
其实,这些仍然需要借助于awk、sed、grep这些超牛的命令工具。优先选择的就是awk。
方案一:记录分隔符方式
第一个举例,我们可以如下去除掉注释内容:
cat tomcat-users.xml |awk 'BEGIN{RS="<!--|-->"}NR%2' |grep -v '^\s*$'这条命令很巧妙,完美解决该问题。
小知识:
RS(record separator):输入的记录分隔符,默认为换行符。
NR(number of input records):已经读出的记录数,就是行号,从1开始,不论读取多少文件都不会从头开始记录。有别于FNR。
FNR:当前记录数,或当前读取文件中记录数,读取下一个文件时FNR从1开始
首先在BEGIN{}体中设置RS为 <!-- 或 -->,将处理单元,从行级转变成块;然后NR(这里就不是行号了,是块号)取模运算:当记录号为奇数时返回1(真),偶数时返回0(假)。这样只会打印没有被注释的内容(即便是<!-- …… -->单行注释)。
方案二:状态机方式
比上一个方案略显复杂,但是更容易理解。便于添加额外处理逻辑。可维护性也好。
cat tomcat-users.xml|awk 'BEGIN{is_note=0
}{if($0~/^[[:space:]]*<!--/){is_note=1}if($0~/-->[[:space:]]*$/){is_note=0;next}if(!is_note && $0 !~ /^[[:space:]]*$/)print
}'作业
那么,学会了上述两种方法,你是否可以解决第二个举例了呢?
