我有一个文件,想使用 grep 来排除模式。但我也想删除每场比赛的前 2 行(不包括在内(。我该怎么做?
我尝试过的:
cat file.txt
Sequence: MG719312_IGHV1-8*03_Homosapiens_F_V-REGION_127..422_296nt_1_____296+0=296___ from: 1 to: 296
Start End Strand Pattern Mismatch Sequence
217 225 + pattern:AA[CT]NNN[AT]CN . aacacctcc
Sequence: M99648_IGHV2-26*01_Homosapiens_F_V-REGION_164..464_301nt_1_____301+0=301___ from: 1 to: 301
Start End Strand Pattern Mismatch Sequence
176 184 + pattern:AA[CT]NNN[AT]CN . aatcctaca
# With grep -v I can remove the line with pattern
grep -v "[acgt]{3}cc[acgt][acgt]{3}" file.txt
Sequence: MG719312_IGHV1-8*03_Homosapiens_F_V-REGION_127..422_296nt_1_____296+0=296___ from: 1 to: 296
Start End Strand Pattern Mismatch Sequence
217 225 + pattern:AA[CT]NNN[AT]CN . aacacctcc
Sequence: M99648_IGHV2-26*01_Homosapiens_F_V-REGION_164..464_301nt_1_____301+0=301___ from: 1 to: 301
Start End Strand Pattern Mismatch Sequence
# But using -B 2 does not work here
grep -B 2 -v "[acgt]{3}cc[acgt][acgt]{3}" file.txt
Sequence: MG719312_IGHV1-8*03_Homosapiens_F_V-REGION_127..422_296nt_1_____296+0=296___ from: 1 to: 296
Start End Strand Pattern Mismatch Sequence
217 225 + pattern:AA[CT]NNN[AT]CN . aacacctcc
Sequence: M99648_IGHV2-26*01_Homosapiens_F_V-REGION_164..464_301nt_1_____301+0=301___ from: 1 to: 301
Start End Strand Pattern Mismatch Sequence
任何想法如何删除每场比赛的前 2 行?
在GNU sed
上测试,语法/功能可能因其他实现而异
sed -E 'N;N; /[acgt]{3}cc[acgt][acgt]{3}/d' ip.txt
-
-E
使用 ERE,某些 sed 版本需要-r
而不是-E
-
N;N
将另外两行追加到图案空间 - 如果此条件匹配,则
/[acgt]{3}cc[acgt][acgt]{3}/d
删除- 请注意,这将尝试匹配三行中任何位置的正则表达式......此外,
[acgt][acgt]{3}
可以简化为[acgt]{4}
-
/n.*n.*[acgt]{3}cc[acgt][acgt]{3}/d
将限制为仅匹配第 3 行
- 请注意,这将尝试匹配三行中任何位置的正则表达式......此外,
您所需要的只是:
tac file | awk '/regexp/{c=3} !(c&&c--)' | tac
显然,regexp
设置为您要匹配的任何正则表达式,并将3
更改为要跳过的行数,包括匹配行。 例如,跳过包含7
的每一行及其前面的 4 行:
$ seq 20 | tac | awk '/7/{c=5} !(c&&c--)' | tac
1
2
8
9
10
11
12
18
19
20
请参阅 https://stackoverflow.com/a/17914105/1745001,了解如何在匹配行周围打印您喜欢的任何行。
以您的示例为例:
$ tac file | awk '/[acgt]{3}cc[acgt][acgt]{3}/{c=3} !(c&&c--)' | tac
Sequence: MG719312_IGHV1-8*03_Homosapiens_F_V-REGION_127..422_296nt_1_____296+0=296___ from: 1 to: 296
Start End Strand Pattern Mismatch Sequence
217 225 + pattern:AA[CT]NNN[AT]CN . aacacctcc
现在,您可能需要为数据考虑一些事项:
$ cat tst.awk
++lineNr == 1 {
delete fldNr2tag
delete tagNr2tag
delete tag2val
numTags = 0
for (i=1; i<=NF; i+=2) {
sub(/:.*/,"",$i)
tag = $i (i>1 ? "" : 1) # to distinguish the 2 "Sequence" tags
val = $(i+1)
tagNr2tag[++numTags] = tag
tag2val[tag] = val
}
}
lineNr == 2 {
for (i=1; i<=NF; i++) {
tag = $i
fldNr2tag[i] = tag
}
}
lineNr == 3 {
for (i=1; i<=NF; i++) {
tag = fldNr2tag[i]
val = $i
tagNr2tag[++numTags] = tag
tag2val[tag] = val
}
prt()
lineNr = 0
}
function prt( tagNr, tag, val) {
for (tagNr=1; tagNr<=numTags; tagNr++) {
tag = tagNr2tag[tagNr]
val = tag2val[tag]
printf "tag2val[%s] = <%s>n", tag, val
}
print "----"
}
.
$ awk -f tst.awk file
tag2val[Sequence1] = <MG719312_IGHV1-8*03_Homosapiens_F_V-REGION_127..422_296nt_1_____296+0=296___>
tag2val[from] = <1>
tag2val[to] = <296>
tag2val[Start] = <217>
tag2val[End] = <225>
tag2val[Strand] = <+>
tag2val[Pattern] = <pattern:AA[CT]NNN[AT]CN>
tag2val[Mismatch] = <.>
tag2val[Sequence] = <aacacctcc>
----
tag2val[Sequence1] = <M99648_IGHV2-26*01_Homosapiens_F_V-REGION_164..464_301nt_1_____301+0=301___>
tag2val[from] = <1>
tag2val[to] = <301>
tag2val[Start] = <176>
tag2val[End] = <184>
tag2val[Strand] = <+>
tag2val[Pattern] = <pattern:AA[CT]NNN[AT]CN>
tag2val[Mismatch] = <.>
tag2val[Sequence] = <aatcctaca>
----
请注意,通过上述内容,您可以按其名称访问每个值,从而从比较或其他计算中删除不精确和/或错误的匹配,并且您可以选择特定字段以您喜欢的任何顺序打印,只需使用字段名称,例如 print tag2val["Sequence"], tag2val["Pattern"]
.因此,您可以简单地将数据转换为CSV,以便导入Excel或转换为HTML或JSON,或者对其进行其他任何操作。
查看示例文件,它似乎具有面向记录的结构,因此我会非常谨慎地尝试使用面向行的工具(如 grep
和 sed
(来操作它。正如评论中指出的那样,sed
中的解决方案已经存在类似的问题,但脚本并不漂亮,维护或扩展将是一场噩梦。
我很想写一个简短的Perl或Python脚本来将文件解析为记录,然后处理记录。我不知道文件格式的细节,但像下面这样的东西可能是一个好的开始,并产生你想要的输出。
#!/usr/bin/perl -w
use strict;
my $line = <>;
unless (defined($line) && $line =~ /^Sequence/) {
die "expected line to start with Sequence";
}
while (defined($line)) {
my $record = $line;
$line = <>;
while (defined($line) && $line !~ /^Sequence/) {
$record .= $line;
$line = <>;
}
print $record unless $record =~ /[acgt]{3}cc[acgt][acgt]{3}/;
}