grep
我想知道如果字符串不出现在同一行,我们如何在块内使用 AND 条件表示两个字符串。我尝试了以下方法,但它们不适用于不在同一行的字符串:-
grep 'string1.*string2\|string2.*string1' filename
grep -P '^(?=.*pattern1)(?=.*pattern2)' filename
例如我有一个包含以下几行的 xml 文件:-
<test-result
exectime="2017-07-07"
result="FAILURE"
isdone="TRUE"
logicalname="this.is.test1"
duration="10050"
>
<test-case
testcasename="this.is.test.case.name1"
testunit="abcd-mc"
testpath="file:/this/is/the/file/path1/abcd.xml"
>
</test-case>
</test-result>
<test-result
exectime="2017-07-07"
result="SUCCESS"
isdone="TRUE"
logicalname="this.is.test1"
duration="10050"
>
<test-case
testcasename="this.is.test.case.name1"
testunit="abcd-mc"
testpath="file:/this/is/the/file/path1/uvwx.xml"
>
</test-case>
</test-result>
请注意,标签内的 2 个代码块<test-result></test-result>
在testpath
.所以,我想grep
为logicalname
和result
( grep
this.is.test1
AND FAILURE
) 找到testpath
同一个块的相应值。
接下来,一旦我有了testpath
场景的FAILURE
,我如何修改文件以使结果适合SUCCESS
带有“testpath
我找到的”和logicalname
?
答案1
我的建议是“甚至不用费心尝试这样做grep
”。您可能会在awk
or中敲出一些不可靠的基于正则表达式的 hack perl
,但正则表达式不能可靠地用于从 XML 中解析或提取数据。无论你想到什么,很可能都是一团难以阅读和难以维护的混乱。还有更好的方法。实际有效且可靠的方法。
简而言之:不要解析 XML 或 HTML用正则表达式。它不起作用。
相反,使用 xml 解析器,例如xmlstarlet。或者,使用类似perl
或 的语言python
,这两种语言都有多个 XML 解析库可供选择。
如果您确实想使用面向行的工具grep
(或者更好的是awk
or perl
,甚至sed
)处理 XML,请首先使用以下命令将 xml 转换为面向行的格式:XML2。对于从 XML 文件中非常简单地提取数据来说,这是一个不错的选择。
例如,在修复了示例 xml 中最明显的错误后,以下是使用以下命令处理后的样子xml2
:
$ xml2 < ajs.xml
/xml/test-result/@exectime=2017-07-07
/xml/test-result/@result=FAILURE
/xml/test-result/@isdone=TRUE
/xml/test-result/@logicalname=this.is.test1
/xml/test-result/@duration=10050
/xml/test-result/test-case/@testcasename=this.is.test.case.name1
/xml/test-result/test-case/@testunit=abcd-mc
/xml/test-result/test-case/@testpath=file:/this/is/the/file/path1/abcd.xml
/xml/test-result
/xml/test-result/@exectime=2017-07-07
/xml/test-result/@result=SUCCESS
/xml/test-result/@isdone=TRUE
/xml/test-result/@logicalname=this.is.test1
/xml/test-result/@duration=10050
/xml/test-result/test-case/@testcasename=this.is.test.case.name1
/xml/test-result/test-case/@testunit=abcd-mc
/xml/test-result/test-case/@testpath=file:/this/is/the/file/path1/uvwx.xml
仅使用 很难获得您想要的东西grep
,但是使用perl
(只需简单的 perl 而不使用 XML 库)或相当容易awk
,并且使用 也不太困难sed
。
使用或xmlstarlet
中的 XML 解析库会更容易。所有这些方法都直接处理 XML 文档中的结构化数据,即将每个 XML 元素作为具有可选属性和值的不同对象来处理,而不仅仅是一堆可能以某种方式连接的行。perl
python
顺便说一句,有很多问题都有很好的答案xmlstarlet和XML2在这个网站上。
xml2
和都xmlstarlet
针对大多数 Linux 发行版进行了预打包。
最后,尝试从至少结构合理的 XML 开始。上面的示例 XML 有几个缺陷。任何工具都很难解析损坏的、不完整的或不符合标准的 XML 输入。
答案2
注意到“解析 XML 是不好的做法”,这里是awk
您问题的解决方案:)
awk -v RS="<test-result" '
/logicalname="this\.is\.test1"/&&/result="FAILURE"/ {
sub("FAILURE","SUCCESS")
}1' RS='' infile.txt
在上面,我们告诉awk
我们右埃科德SeperatorRS
是<test-result
,那么对于每个记录,将查找两个模式(logicalname="this.is.test1"
和result="FAILURE"
),如果它在那里(在同一个块内),则从FAILURE
给SUCCESS
定的更改为infile.txt
正如我们在评论中所说,因为您想使用 更改特定块testpath=....
,您可以仅向命令添加另一个第三个条件。仅当也看到时,下面才会改变testpath="file:/this/is/the/file/path1/abcd.xml"
。
请注意,您需要 escape /
,并且最好也 escape .
s 。
awk -v RS="<test-result" ' /logicalname="this\.is\.test1"/&&/result="FAILURE"/&&/testpath="file:\/this\/is\/the\/file\/path1\/abcd\.xml"/
{sub("FAILURE","SUCCESS")
}1' RS='' infile.txt