我有一个文本文件,其中包含以'TITLE'和'DATA'开头的交换行,但有时会出现以'TITLE'开头的重复行:
TITLE something DATA一些数据
标题别的东西
DATA其他一些数据
标题更多 标题额外信息
数据更多数据
我希望能够检测以'TITLE'开头的重复行,并且只保留每对这样的第一行。
我发现用于捕获它们的正则表达式是^TITLE.*\n^TITLE.*\n
现在我想将其合并为一行perl
/ bash
/ sed
/ {{1将删除第二行并输出文件的其余部分的命令,但我无法解决这个问题。
答案 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