grep特定行,将上行打印到特定单词和/或下面的行到特定单词

时间:2014-10-08 12:43:44

标签: bash design-patterns awk sed grep

我最近遇到了一个问题,我似乎找不到一致的解决方案。

假设我们有一些xml文件,它的构建如下:

...
<tenant>
  <name>bla</name>
  <id>1</id>
  <something>whatever</something>
</tenant>
<tenant>
  <name>foo</name>
  <id>55</id>
  <something>whatever</something>
</tenant>
<tenant>
  <name>waaaaaaaaaaaaaaaey</name>
  <id>8013</id>
  <something>what</something>
</tenant>
...

让我们说甚至可能有更多选项,如<e-mail>和其他一些东西。所以它真的可以改变那里的长度。 现在我们知道它是“什么”的“东西”和它的grep。但我们不仅希望获得该结果,而且希望<tenant></tenant>之间的所有结果都包含<something>whatever</something>。 由于行数可能在<tenant></tenant>之间变化,因此我不能在grep上使用-A,-B或-C。 任何帮助都会在这里得到解决。 我目前只做-C足够大,所以我至少有所有的信息,但也许一旦长度会更长,我的方法搞砸了。

4 个答案:

答案 0 :(得分:2)

awk / grep / sed(正则表达式)不适合您的要求。因为我对你的问题的理解是:

  • 有效的xml文件
  • 文本格式可能不同,元素可能会有所不同,可能会分为几行,也可能包含空行。

所以,xpath是正确的方法:

 //tenant[something='whatever']

更改somethingwhatever您将获得相应的tenant元素。

如果您更喜欢使用linux cmd工具,xmllint就是一个例子:

 xmllint --xpath "//tenant[something='whatever']" your.xml

答案 1 :(得分:1)

将GNU awk用于多字符RS和RT:

$ awk -v RS='</tenant>' '/<something>whatever<\/something>/{print $0 RT}' file
<tenant>
  <name>bla</name>
  <id>1</id>
  <something>whatever</something>
</tenant>

<tenant>
  <name>foo</name>
  <id>55</id>
  <something>whatever</something>
</tenant>

答案 2 :(得分:0)

以下pcregrep只有在包含字符串<something>whatever</something>

时才会获取租户标记之间的内容
$ pcregrep -M -o '(?s)<tenant>\n\K.*?<something>whatever<\/something>.*?(?=\n<\/tenant>)' file
  <name>bla</name>
  <id>1</id>
  <something>whatever</something>
  <name>foo</name>
  <id>55</id>
  <something>whatever</something>

使用<tenant>代码。

$ pcregrep -M -o '(?s)<tenant>\n.*?<something>whatever<\/something>.*?<\/tenant>' file
<tenant>
  <name>bla</name>
  <id>1</id>
  <something>whatever</something>
</tenant>
<tenant>
  <name>foo</name>
  <id>55</id>
  <something>whatever</something>
</tenant>

答案 3 :(得分:0)

这可能适合你(GNU sed):

sed -n '/<tenant>/{:a;N;\|</tenant>|!ba;\|<something>whatever</something>|p}' file
相关问题