编辑:之前没有提及要在OS X中执行
我正在尝试创建一个bash脚本,它将从文件中删除一些块并将结果保存到另一个块。
我要过滤的文件内容应如下所示:
<element>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
</element>
<element>
<subElement name="removeme"/>
<subElement name="removeme"/>
<subElement name="removeme"/>
</element>
<element>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
</element>
我要移除的是包含<element></element>
标记的群组,其中包含子元素<subElement name="removeme"/>
保证没有任何组合将“removeme”和“leaveme”元素混合在一起。
我知道如何使用这样的正则表达式执行此操作:
<element>(?:(?!/elem).)*"removeme".*?</element>
但我真的迷失了如何在shell脚本中做到这一点,找到了一些关于sed的信息,但却不明白如何完成它。
感谢。
答案 0 :(得分:3)
Regular expressions are certainly the wrong tool to parse XML。您希望XML处理工具删除与xpath //element[subElement[@name="removeme"]]
element
个subElement
子节点,其name
属性值为removeme
使用xmlstarlet
:
xmlstarlet ed -d '//element[subElement[@name="removeme"]]' << ENDXML
<elements>
<element>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
</element>
<element>
<subElement name="removeme"/>
<subElement name="removeme"/>
<subElement name="removeme"/>
</element>
<element>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
</element>
</elements>
ENDXML
<?xml version="1.0"?>
<elements>
<element>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
</element>
<element>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
</element>
</elements>
答案 1 :(得分:1)
以下内容(基于Jotne的帖子here)是收集lines
数组中文件的所有行。 <element>
和</element>
代码的位置分别保存在i_start
和i_end
中。如果看到<subElement name="removeme"/>
,则found
设置为1
(true)。如果i_end
为真,则0
有条件地设置为found
,如果found
不为真,则{ - 1}}设置为结束元素的行号(数组索引)。如果i_end
不为零,则打印开始和结束标记之间的块。
awk '
{ lines[NR] = $0 }
/<element>/ { i_start = NR }
/<\/element>/ { i_end = found ? 0 : NR; found = 0 }
/<subElement name="removeme"\/>/ { found = 1 }
i_end {
for (i = i_start; i <= i_end; i++)
print lines[i]
i_end = 0;
}
' file
答案 2 :(得分:1)
使用gnu awk
你可以这样做:
awk -v RS="<element>" '!/removeme/ && NR>1{print RS $0}' file
<element>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
</element>
<element>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
<subElement name="leaveme"/>
</element>
通过将RS
设置为<element>
,您告诉awk
以阻止模式工作,并以<element>
开头
然后,!/removeme/
告诉awk
不要使用removeme
数据打印该块。
答案 3 :(得分:0)
使用sed:
sed -n '
/<element>/h
/<element>/!H
/<\/element>/{g;/<subElement name="removeme"\/>/!p;}
' file
/<element>/h
命令初始化匹配保留空间和模式空间内容。
如果行与/<element>/!H
不匹配,<element>
命令会将模式空间内容附加到保留空间。
/<\/element>/{g;/<subElement name="removeme"\/>/!p}
命令测试结束标记和匹配执行后续两个命令:
element
块的更新模式空间。