fqdns
我想从以下文件中提取内容,但仅限于每个device
位置:status
new
<device id='10.72.48.215'>
<address>10.72.48.215</address>
<status>old</status>
<fqdns>10.72.48.215</fqdns>
<parent></parent>
<type>Unknown</type>
<ports>
</ports>
<operatingsystems>
</operatingsystems>
</device>
<device id='10.72.48.216'>
<address>10.72.48.216</address>
<status>new</status>
<fqdns>10.72.48.216</fqdns>
<parent></parent>
<type>Unknown</type>
<ports>
</ports>
<operatingsystems>
</operatingsystems>
</device>
因此,对于上述内容,我想获得10.72.48.216
(而不是10.72.48.215
)。
答案1
如果添加 XML 声明并将两个device
元素包含在顶级元素中,则可以使用 XPath 处理文件:
$ cat ./248127.xml
<device id='10.72.48.215'>
<address>10.72.48.215</address>
<status>old</status>
<fqdns>10.72.48.215</fqdns>
<parent></parent>
<type>Unknown</type>
<ports>
</ports>
<operatingsystems>
</operatingsystems>
</device>
<device id='10.72.48.216'>
<address>10.72.48.216</address>
<status>new</status>
<fqdns>10.72.48.216</fqdns>
<parent></parent>
<type>Unknown</type>
<ports>
</ports>
<operatingsystems>
</operatingsystems>
</device>
$ ( echo '<?xml version="1.0"?><doc>'; cat ./248127.xml ; echo '</doc>' ) \
| xpath -q -e '//device[status/text()="new"]/fqdns'
<fqdns>10.72.48.216</fqdns>
答案2
您可以使用 pcrgrep 命令来完成此操作,该命令具有多行搜索选项。
pcregrep -M "\<status.*\n.*fqdns\>$"
至于你要求的解释:
所以 -M 表示多行
\< 字符串开头的状态。我必须使用 \ 来获取 < 的含义,因为它对于 shell 来说是特殊的。
然后 。 (任意字符)后面带*表示可以重复。
\n 换行
。对于后跟 * 的字符,因为它可以重复。
然后是字符串 fqdns
并关闭
\> 又是 >,用 \ 表示含义
最后,$ 是行尾
字符串匹配称为正则表达式
答案3
一个简单的grep可以做到这一点:
grep -A1 "<status>new" sample.xml
# <status>new</status>
# <fqdns>10.72.48.216</fqdns>
仅当您的 xml 源稳定并且不会更改行的顺序时才建议这样做。 (我修改了你的示例,在第二个块中有一个“新”。)
您可以使用更多 grep 过滤以下行:
grep -A1 "<status>new" sample.xml | grep "<fqdns>"
# <fqdns>10.72.48.216</fqdns>
和sed,您可以轻松提取 IP:
sed -rn '/<status>new/{n; s/.*<fqdns>(.*)<\/fqdns>/\1/p}' sample.xml
# 10.72.48.216
它匹配<status>new
并读取n外线和s替代品<fqdns>
和结束标签之间的部分。这-n告诉 sed “默认情况下不打印”,“-r”允许在不屏蔽的情况下写入正则表达式(这里是 .* 周围的括号)。