[英]How to remove blocks of text from file
编辑:在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的一些信息,但不了解如何完成。
谢谢。
正则表达式当然是解析XML的错误工具 。 您想要一个XML处理工具来删除与xpath匹配的节点//element[subElement[@name="removeme"]]
subElement
子项的element
节点,该子element
节点具有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>
接下来的想法(基于Jotne的here )是将文件的所有行收集到lines
数组中。 <element>
和</element>
标记的位置分别保存在i_start
和i_end
。 如果看到<subElement name="removeme"/>
,则将found
设置为1
(true)。 i_end
有条件地设置为0
,如果found
如果是端部元件的真实或行号(数组索引) found
是不正确的。 如果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
使用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
数据的块。
使用sed:
sed -n '
/<element>/h
/<element>/!H
/<\/element>/{g;/<subElement name="removeme"\/>/!p;}
' file
/<element>/h
命令在将保持空间与模式空间内容匹配时进行初始化。
如果行与<element>
不匹配,则/<element>/!H
命令会将模式空间内容追加到保留空间。
/<\\/element>/{g;/<subElement name="removeme"\\/>/!p}
命令测试结束标记,并在匹配时执行以下两个命令:
element
块的更新后的模式空间进行测试。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.