2

我通常使用大型 XML 文件,并且通常通过字数grep来确认某些统计数据。

例如,我想通过以下方式确保widget在一个 xml 文件中至少有五个实例:

cat test.xml | grep -ic widget

此外,我只是希望能够记录widget出现的行,即:

cat test.xml | grep -i widget > ~/log.txt

但是,我真正需要的关键信息是出现在其中的 XML 代码块widget。示例文件可能如下所示:

<test> blah blah
  blah blah blah
  widget
  blah blah blah
</test>

<formula>
  blah
  <details> 
    widget
  </details>
</formula>

我试图从上面的示例文本中获取以下输出,即:

<test>widget</test>

<formula>widget</formula>

实际上,我试图获得具有最高级别标记标签的单行,这些标记标签适用于围绕任意字符串的 XML 文本/代码块,widget.

有没有人有任何建议通过命令行一个班轮实现这一点?

谢谢你。

4

4 回答 4

3

sed一种同时使用and的非优雅方式awk

sed -ne '/[Ww][Ii][Dd][Gg][Ee][Tt]/,/^<\// {//p}' file.txt | awk 'NR%2==1 { sub(/^[ \t]+/, ""); search = $0 } NR%2==0 { end = $0; sub(/^<\//, "<"); printf "%s%s%s\n", $0, search, end }'

结果:

<test>widget</test>
<formula>widget</formula>

解释:

## The sed pipe:

sed -ne '/[Ww][Ii][Dd][Gg][Ee][Tt]/,/^<\// {//p}'
## This finds the widget pattern, ignoring case, then finds the last, 
## highest level markup tag (these must match the start of the line)
## Ultimately, this prints two lines for each pattern match

## Now the awk pipe:

NR%2==1 { sub(/^[ \t]+/, ""); search = $0 }
## This takes the first line (the widget pattern) and removes leading
## whitespace, saving the pattern in 'search'

NR%2==0 { end = $0; sub(/^<\//, "<"); printf "%s%s%s\n", $0, search, end }
## This finds the next line (which is even), and stores the markup tag in 'end'
## We then remove the slash from this tag and print it, the widget pattern, and
## the saved markup tag

高温高压

于 2012-07-20T23:56:51.427 回答
2
 sed -nr '/^(<[^>]*>).*/{s//\1/;h};/widget/{g;p}' test.xml

印刷

<test>
<formula>

如果打印您想要的确切格式,则 Sed only one-liner 会更复杂。

编辑:
您可以在 gnu sed 中使用/widget/I而不是/widget/不区分大小写的匹配,否则就像在其他答案中一样使用每个字母。widget[Ww]

于 2012-07-21T05:17:57.933 回答
2

这可能对你有用(GUN sed):

sed '/^<[^/]/!d;:a;/^<\([^>]*>\).*<\/\1/!{$!N;ba};/^<\([^>]*>\).*\(widget\).*<\/\1/s//<\1\2<\/\1/p;d' file
于 2012-07-21T08:40:43.023 回答
1

需要gawk有正则表达式RS

BEGIN {
    # make a stream of words
    RS="(\n| )"
}

# match </tag>
/<\// {
    s--
    next
}

# match <tag>
/</ {
    if (!s) {
    tag=substr($0, 2)
    }
    s++
}

$0=="widget" {
    print "<" tag $0 "</" tag
}
于 2012-07-27T18:41:35.713 回答