如何删除以相同单词开头的第二行连续行?

时间:2013-03-15 11:08:11

标签: regex perl bash sed awk

我有一个文本文件,其中包含以'TITLE'和'DATA'开头的交换行,但有时会出现以'TITLE'开头的重复行:

  

TITLE something   DATA一些数据
  标题别的东西
  DATA其他一些数据
  标题更多   标题额外信息
  数据更多数据

我希望能够检测以'TITLE'开头的重复行,并且只保留每对这样的第一行。
我发现用于捕获它们的正则表达式是^TITLE.*\n^TITLE.*\n现在我想将其合并为一行perl / bash / sed / {{1将删除第二行并输出文件的其余部分的命令,但我无法解决这个问题。

5 个答案:

答案 0 :(得分:6)

这是使用GNU sed执行此操作的一种方法:

sed -r 'N; /(TITLE)[^\n]*\n\1/ s/\n.*//; P; D' infile
  • N将第二行放入模式空间。
  • 匹配测试两行是否以TITLE开头。
  • 如果是,则删除第二行。
  • P; D打印并删除模式空间中的第一行。

输出:

TITLE something
DATA some data
TITLE something else
DATA some other data
TITLE some more
DATA some more data

编辑 - 处理任意重复次数

正如 Nikina Reklawyks 在评论中所指出的,上述解决方案仅适用于以TITLE开头的两个连续行,处理任意数量的重复,可以添加一个简单的循环,如下所示:

sed -r ':a; N; /(TITLE)[^\n]*\n\1/ s/\n.*//; ta; P; D' infile

ta成功时,:a语句会将sed跳转到s///标签。

另一种方法是使用uniq中的coreutils命令,这不是那么灵活,但在这种情况下效果很好:

uniq -w5 infile 

答案 1 :(得分:4)

一种方式:

awk '$1!=p{print;p=$1}' file

答案 2 :(得分:3)

Perl解决方案:

perl -ne 'print unless $t and /^TITLE/; $t = /^TITLE/'

它会记住上一行是否是$t变量中的TITLE。

答案 3 :(得分:2)

听起来像你有两个字段,TITLE和DATA组成的记录,如果你错过了第二个字段,你想删除记录。但这不是你在问题中提出的问题。所以这是一种做你问过的方法:

awk '/^TITLE/&&!t{t=$0} /^DATA/&&t{print t;print;t=""}' inputfile

这里的想法是,当我们看到它并且还没有标题集时,我们将变量设置为TITLE,然后只在我们看到DATA时打印它。如果我正确地阅读您的问题,这适用于您提供的输入数据。输出是:

TITLE something
DATA some data
TITLE something else
DATA some other data
TITLE some more
DATA some more data

如您所见,数据集中的最后一条TITLE行已被删除。

这是另一种在awk中执行此操作的方法...

awk '/^TITLE/&&t{next} t=0; /^TITLE/{t=1} 1' inputfile

在这一个中,如果t已设置,则第一个表达式会跳过标题。第二个表达式取消设置t。第三个表达式设置是否为标题,最后一个表达式(1)打印该行。当然,如果我们跳过第一个表达式中的行,则最后三个表达式不会运行。它生成与上面相同的输出,并且不会费心查看/^DATA/

最后,这个是最少的代码,但是最奇怪的逻辑:

awk '/^DATA/ || !t; {t=/^TITLE/}' inputfile

它打印所有数据行或未设置t的任何行,然后有效地将t设置为布尔值,从而影响下一行的评估。如果你在csh或tcsh中这样做,请注意感叹号,这些感叹号可能需要转义。

答案 4 :(得分:1)

试试这个单行:

 awk '/^TITLE/&&f{next;} {if ($0~/^TITLE/)f=1;else f=0}1' file

输出:

TITLE something
DATA some data
TITLE something else
DATA some other data
TITLE some more
DATA some more data