共计 1488 个字符,预计需要花费 4 分钟才能阅读完成。
01 xml 文件
# user.xml
<user>
<name>Toy</name>
<sex>man</sex>
<room/>
</user>
其中第 5 行的<room/>
xml 节点是空节点,是比较特殊的格式。
02 多条命令解析 xml 节点
采用多条命令和管道符也可以解析 xml 节点,方式如下:
[~]$ cat user.xml | grep name | sed 's/^.*<name>//g' | sed 's/<\/name>.*$//g'
Toy
[~]$ cat user.xml | grep name | sed 's/^.*<sex>//g' | sed 's/<\/sex>.*$//g'
[~]$ cat user.xml | grep room | sed 's/^.*<room>//g' | sed 's/<\/room>.*$//g'
<room/>
上面的方式无法解析 <room/>
这种特殊格式的 xml 节点,虽然用多个命令和管道符是可以实现解析正常格式的 xml 节点的值,但是过多的管道符是会降低执行效率的。
因为管道符是会为连接的命令产生子进程,从而加大 CPU 的开销。
03 一行 awk 命令解析 xml 节点
awk 命令解析所有特殊的 xml 节点的值,只需要一行命:
[~]$ awk '/<\/*name\/*>/{gsub(/[[:space:]]*<\/*name\/*>/,"");print $0}' user.xml
Toy
[~]$ awk '/<\/*sex\/*>/{gsub(/[[:space:]]*<\/*sex\/*>/,"");print $0}' user.xml
man
[~]$ awk '/<\/*room\/*>/{gsub(/[[:space:]]*<\/*room\/*>/,"");print $0}' user.xml
[~]$
上面的 awk 方式可以兼容所有特殊的 xml 节点,并且只需要一条命令就能解析出 xml 的值。
简单说明下命令的意思:
-
awk '/ 匹配的字符串 /{print $0}'
表示在文本中,找到匹配的字符串所在的行记录,可以替代grep "匹配的字符串"
-
gsub(/ 匹配的字符串 /,"")
是 awk 内部的函数,表示将匹配到的字符串替换成""
,也就是替换成空字符串,可以替代sed 's/ 匹配的字符串 //g'
-
</*name/*>
中的*
号是正则表达式,*
号表示可以重复前面字符 0 个或多个,所以</*name/*>
可以间接的表示<name>
、</name>
和<name/>
等 -
[[:space:]]
表示匹配空格、制表格等空白符,[[:space:]]*
表示匹配空白字符 0 个或多个 -
$0
表示取记录的所有记录
所以,awk 解析 xml 节点的命令小结成如下:
awk '/<\/* 节点名字 \/*>/{gsub(/[[:space:]]*<\/* 节点名字 \/*>/,"");print $0}' xml 文件
04 小结
我们在编写脚本时,需要解析文本文件时,尽量避免使用多命令和管道符的方式去解析,因为使用了管道符就会产生子进程,会加大了 CPU 的开销。
大部分情况下只需要一条 awk 命令就完成解析的工作,相比较起多命令和管道符的方式效率会更高,并且 CPU 开销小。
通过以上的两个解析 xml 节点的案例,我们可以总结出:
awk '/ 匹配的字符串 /{print $0}' 可以替代 grep "匹配的字符串"
awk '{gsub(/ 匹配的字符串 /,"");print $0}'可以替代 sed's/ 匹配的字符串 /""/g'
awk '/ 匹配的字符串 /{gsub(/ 匹配的字符串 /,"");print $0}' <xml 文件 >
可以替代
cat <xml 文件 > | grep "匹配的字符串" | sed 's/ 匹配的字符串 /""/g'
正文完