对于一组行号...提取不同模式第一次出现和最后一次出现之间的内容

对于一组行号...提取不同模式第一次出现和最后一次出现之间的内容

我在一个文件中有类似的内容。我有一个行号列表,其中有 1,2,4。

  1. 可以满足所有需要的行号
  2. 提取之间的内容第一的和 的出现最后的的发生</book>

数据:

</p><p>abc</p></book><book><p style="text-indent:0em;">def</p></book><book><p>ghi</p><p style="text-indent:0em;"></book><book><div><p>  
</div><p>123</p></book><book><p style="text-indent:0em;">456</p><p>789</p><p style="text-indent:0em;"></book><book><div><p>  
<div><p>nothing !!!</p></div>  
</p><p>ABC</p></book><book><p style="text-indent:0em;">DEF</p></book><book><p>GHI</p><p style="text-indent:0em;"></book><book><div><p>JKL</p></div></book><div>  

输入行号:1, 2, 4(我想在命令中输入)

期望的输出:

<book><p style="text-indent:0em;">def</p></book><book><p>ghi</p><p style="text-indent:0em;"></book>
<book><p style="text-indent:0em;">456</p><p>789</p><p style="text-indent:0em;"></book>
<book><p style="text-indent:0em;">DEF</p></book><book><p>GHI</p><p style="text-indent:0em;"></book><book><div><p>JKL</p></div></book>

答案1

1)提取特定行

在四行示例中,通过删除第三行可以轻松提取第一行、第二行和第四行:

sed 3d file

但你的文件可能更复杂,所以更通用的解决方案是

sed -e 1b -e 2b -e 4b -e d file

因此,对于应保留的每一行,您可以跳到脚本末尾b并删除所有剩余文件。

对于更长的行号列表,您可能需要生成脚本:

sed $(for i in 1 2 4; do echo "-e ${i}b"; done) -e d file

但似乎不是行号的问题,而是<book>该行是否有 s 的问题。如果这是真的,你最好忘记行号并执行

sed '/<book>/!d' 

2)提取内容

正则表达式的贪婪*不适合此类任务。这就是为什么我的个人版本sed有一个命令选项,o可以仅用匹配的部分s替换:o

sed '/<book>/!d;s_<book>.*</book>_&_o' 

但这对你不起作用,所以你需要更多的正则表达式杂耍:

sed '/<book>/!d;s_<book>_\n&_;s_.*\n__;s_\(.*</book>\).*_\1_' file

如果您的版本sed不支持\n替换字符串,请使用实际的换行符(通过反斜杠转义):

sed '/<book>/!d;s_<book>_\
&_;s_.*\n__;s_\(.*</book>\).*_\1_' file

答案2

perl

#!/usr/bin/env perl

use strict;
use warnings;

use v5.10;

my @lines = (1, 2, 4);

while(<>) {
    next unless $. ~~ @lines;
    chomp;
    s#.*?(<book>.*</book>).*#$1#;
    say
}

相关内容