bash使用awk或sed从出现向后搜索到特定的字符串

时间:2016-11-16 17:54:36

标签: bash search awk sed

我有一个xml文件,我在这个文件中搜索一个字符串。 一旦(如果)找到该字符串,我需要能够搜索到另一个字符串的位置并输出数据。

即:

<xml>
<packet>
 <proto>
 <field show="bob">
 </proto>
</packet>
<packet>
 <proto>
 <field show="rumpelstiltskin">
 </proto>
</packet>
<packet>
 <proto>
 <field show="peter">
 </proto>
</packet>

我的意见是:

show="rumpelstiltskin" 

<packet>

我需要得到以下结果(基本上是第二个块);

<packet>
<proto>
<field show="rumpelstiltskin">
</proto>
</packet>

<packet>
<proto>
<field show="rumpelstiltskin">

有成千上万的(wireshark pdml转换)和show =“rumpelstilstkin”可以出现在文件的任何地方,并且该部分可以是任意大小。

之前我已经完成了这项工作,并且非常确定它可以在awk或sed oneliner中使用..任何帮助表示赞赏!

5 个答案:

答案 0 :(得分:3)

您需要将XML视为XML并使用适当的工具。例如,稍微修改XML以使其有效:

<xml>
  <packet>
    <proto>
      <field show="bob"/>
    </proto>
  </packet>
  <packet>
    <proto>
      <field show="rumpelstiltskin"/>
    </proto>
  </packet>
  <packet>
    <proto>
      <field show="peter"/>
    </proto>
  </packet>
</xml>

您可以像这样使用xmllint

xmllint --xpath '//packet[proto/field/@show="rumpelstiltskin"]' file.xml

这将匹配并打印<packet>元素中包含<field show="rumpelstiltskin">的所有<proto>元素的内容。

如果您不想指定完整的层次结构,则可以使用以下内容:

xmllint --xpath '//packet[descendant::field[@show="rumpelstiltskin"]]' file.xml

答案 1 :(得分:2)

您可以使用grep

执行此操作

cat file | grep 'show="rumpelstiltskin"' -B5 | grep 'otherstring'

显然会将-B5调整为您需要保留所需字符串的行数。

答案 2 :(得分:1)

如果您的输入非常简单,那么您需要的是:

$ awk '/<packet>/{buf=""} {buf=buf $0 RS} /rumpelstiltskin/{printf "%s",buf}' file
<packet>
 <proto>
 <field show="rumpelstiltskin">

或者如果您愿意:

$ awk '/<packet>/{buf="";f=0} {buf=buf $0 RS} /rumpelstiltskin/{f=1} f&&/<\/packet>/{printf "%s",buf}' file
<packet>
 <proto>
 <field show="rumpelstiltskin">
 </proto>
</packet>

如果您想在第一次打印后停止阅读输入文件,则只需在其后添加;exit,以便printf "%s",buf变为printf "%s",buf; exit

答案 3 :(得分:0)

所以......你可以一起破解一些可以将文件作为文本文件进行基本解析的东西......

awk -v txt="rumpel" '$0=="<packet>"{s=$0; found=0; next} $0~txt{found=1} {s=s RS $0} $0=="</packet>" && found {print s}' inp.xml

为了便于说明而分解成碎片,这样做可以做到以下几点:

  • -v txt="rumpel" - 设置一个在脚本中使用的变量。请注意,在此示例中,这将作为正则表达式进行评估,但如果您希望将其作为字符串进行搜索,则可以使用index()
  • $0=="<packet>"{s=$0; found=0; next} - 如果我们找到数据包的开头,请重置我们的存储变量(s)和标记(found)。
  • $0~txt{found=1} - 如果我们找到了我们要查找的文字,请设置一个标记。
  • {s=s RS $0} - 将当前行附加到变量
  • $0=="</packet>" && found {print s} - 如果我们在文本末尾找到字符串,请打印。

更好的方法可能是使用本地理解XML的东西来解释XML,但仅使用sed和awk是不可能的。

答案 4 :(得分:0)

这可能适合你(GNU sed):

sed '/<packet>/h;//!H;/rumpelstiltskin/!d;x;q' file

这会将所需的字符串存储在保留空间中,然后将其打印出来并退出。

但是要确保第一个和第二个字符串存在且彼此相邻:

sed '/<packet>/h;//!H;/rumpelstiltskin/!d;x;/<packet>.*rumpelstiltskin/!d;q' file