Unix 命令 grep 上下直到某个文本出现

Unix 命令 grep 上下直到某个文本出现

考虑下面的示例,其中“12345”是整个 xml 的唯一 ID。

<Tag 1>
a
b
c
d
12345
x
y
z
</Tag 1>

我需要一个命令,可以在我的文件中 grep '12345' 并分别转到 和 的上方和下方,<Tag 1>这样</Tag 1>我就可以获得所提供的 id 的 XML 文件。

答案1

您可以使用支持 XML 的解析器直接从 XML 中选取值。首先,让我们修复您的 XML 片段以使其有效,并将其放入file.xml

<?xml version="1.0"?>
<Tag_1>
a
b
c
d
12345
x
y
z
</Tag_1>

(1) 知道元素名称后,您可以使用此命令来选取值:

xmlstarlet select -t -v '//Tag_1' file.xml

输出(根据 XML,包括一个前导空行):

a
b
c
d
12345
x
y
z

如果您确实想要元素标签名称,您可以将其再次添加回来:

xmlstarlet select -t -e Tag_1 -v '//Tag_1' file.xml; echo

在这两种情况下,选择器//Tag_1都会匹配所有出现的元素Tag_1。您可以而且应该使用 XPath 选择器更加精确。例如,通过此代码片段,您可以选择stuff使用/root/item/Tag_1

<root>
    <item><Tag_1>stuff</Tag_1></item>
    <unwanted><Tag_1>nonsense</Tag_1></unwanted>
</root>

(2)令我震惊的是,我误读了这个问题,而您实际上想要与所需内容相匹配的元素名称。在这种情况下,它是一个更复杂的表达但这将为您提供包含所需文本的直接元素名称12345

xmlstarlet select -t -m '//*[contains(text(), "12345")]' -m 'ancestor::*' -b -v 'name()' -n file.xml

输出

Tag_1

如果需要,您可以使用此解决方案来识别元素,然后使用我之前的解决方案来提取相应的数据,或者您可以扩展此解决方案的表达式以也包含内容:

xmlstarlet select -T -t -m '//*[contains(text(), "12345")]' -m 'ancestor::*' -b -v 'concat("<", name(), ">", ., "</", name(), ">")' -n file.xml

如果您没有,xmlstarlet您应该会发现它是一个标准软件包并且非常容易安装。或者让您的系统管理员为您安装。

答案2

假设你有文件名text.xml,我们想从上面的搜索字符串中获取数据,即12345.

Grep以上内容

string=`grep -n 12345 text.xml | awk -F: '{print $1}'` && head -n -$(( string - 1 )) text.xml

输出将如下所示 -

<Tag 1>
a
b
c
d

Grep下面的内容

string=`grep -n 12345 text.xml | awk -F: '{print $1}'` && tail -n +$(( string + 1 )) text.xml

输出将如下所示 -

12345
x
y
z
</Tag 1>

答案3

使用(以前称为 Perl_6)

~$ raku -MXML -e 'my @xml = open-xml($*ARGFILES.Str).getElementsByTagName("tag");  \
                  .put for @xml.grep(/12345/);'  file

使用Raku的XML模块解析XML:

https://github.com/raku-community-modules/XML

输入示例:

<?xml version="1.0"?>
<catalog>
  <tag id="1">
  a
  b
  c
  d
  12345
  x
  y
  z
  </tag>
</catalog>

示例输出:

<tag id="1">
  a
  b
  c
  d
  12345
  x
  y
  z
  </tag>

如果你想删除标签(返回contents),并且只返回包含前导空格的char-acter ,那么只需要求 Raku 将其提供给你:linestrim

~$ raku -MXML -e 'my @xml = open-xml($*ARGFILES.Str).getElementsByTagName("tag").map(*.contents);  \
                  .trim-leading.put if .chars for @xml.grep(/12345/).lines;' file 
a
b
c
d
12345
x
y
z

https://raku.org

相关内容