>我有一个制表符分隔的文件,看起来像这样
chr1 12226559 12227059 TNFRSF1B
chr1 17051560 17052060
chr1 17053279 17053779
chr1 17338423 17338923 ATP13A2
ATP13A2
ATP13A2
chr1 19577574 19578074 EMC1
MRTO4
chr1 19578046 19578546 EMC1
MRTO4
chr1 19638239 19638739 AKR7A2
PQLC2
PQLC2
PQLC2
AKR7A2
PQLC2
我希望应该删除重复列 4 值的行。
前三列是坐标,在这些坐标中列出了我们找到的任何内容(在 col4 中),对于每个坐标,我只想有唯一的名称,而不是重复的名称。
我想要这样的输出
chr1 12226559 12227059 TNFRSF1B
chr1 17051560 17052060
chr1 17053279 17053779
chr1 17338423 17338923 ATP13A2
chr1 19577574 19578074 EMC1
MRTO4
chr1 19578046 19578546 EMC1
MRTO4
chr1 19638239 19638739 AKR7A2
PQLC2
我尝试过的事情
sort -k 4 -u file
awk '{if($4==temp1){next;}else{print}temp1=$4}' file
没有任何效果:(
请帮忙
谢谢
你只需要
awk '$NF != prev {print} {prev=$NF}'
编辑:处理新输入
awk '{
if (NF == 1)
value = $1
else {
key = $1 SUBSEP $2 SUBSEP $3
value = $4
}
if ((key SUBSEP value) in val)
next
print
val[key, value] = 1
}' input
sed '1{x;d};H;x;s/([ ][^n ]*)[ ]*n[ ]*1[ ]*n/1n/;$p;x;d;$p;x;d' FILE
如果文件中有制表符,除了空格之外,您可以将所有[ ]
替换为 [[:space:]]
。
简单的awk
脚本
awk -F't' '{OFS="t"; if ($4=="" || $4!=old) print; old=$4}' input.txt
结果
chr1 12226559 12227059 TNFRSF1B
chr1 17051560 17052060
chr1 17053279 17053779
chr1 17338423 17338923 ATP13A2
chr1 19577574 19578074 EMC1
MRTO4
chr1 19578046 19578546 EMC1
MRTO4
chr1 19638239 19638739 AKR7A2
PQLC2
清洗
为了准备我的input.txt
文件,我复制了问题中的文本。但是我不得不用制表符替换空格。因此,我使用了sed
命令。我还注意到一些尾随空格(在行尾)。最后,我使用以下sed
命令来清理输入文件:
sed 's/ *$//;/^[^ ]/s/ */t/g;/^ /s/ */ttt/g;' copy-fron-so.txt > input.txt
来自@dogbane注释的输入文件
chr1 12226559 12227059 TNFRSF1B
chr1 17051560 17052060
chr1 17053279 17053779
chr1 17338423 17338923 ATP13A2
ATP13A2
ATP13A2
chr1 19577574 19578074 EMC1
MRTO4
chr1 19578046 19578546 EMC1
MRTO4
chr1 19638239 19638739 AKR7A2
PQLC2
PQLC2
PQLC2
AKR7A2
(最后一行已附加)
清洁和加工
$> sed 's/ *$//;/^[^ ]/s/ */t/g;/^ /s/ */ttt/g;' copypaste.txt > input.txt
$> awk -F't' '{OFS="t"; if ($4=="" || $4!=old) print; old=$4}' input.txt
chr1 12226559 12227059 TNFRSF1B
chr1 17051560 17052060
chr1 17053279 17053779
chr1 17338423 17338923 ATP13A2
chr1 19577574 19578074 EMC1
MRTO4
chr1 19578046 19578546 EMC1
MRTO4
chr1 19638239 19638739 AKR7A2
PQLC2
AKR7A2
需求变更
不应打印具有AKR7A2
的最后一行。因此,我们首先需要对input.txt
文件进行排序。请注意,选项-t
用于引入选项卡,在bash
或vi
按 [CTRL-V]
,然后[TAB]
(在此选项卡周围加上引号)。
$> LANG=C sort -k 4 -s -t ' ' input.txt > sorted.txt
$> awk -F't' '{OFS="t"; if ($4=="" || $4!=old) print; old=$4}' sorted.txt
chr1 17051560 17052060
chr1 17053279 17053779
chr1 19638239 19638739 AKR7A2
chr1 17338423 17338923 ATP13A2
chr1 19577574 19578074 EMC1
MRTO4
PQLC2
chr1 12226559 12227059 TNFRSF1B
请注意,现在有一行以 MRTO4
结尾!
也许以下内容会有所帮助:
use strict;
use warnings;
my %seen;
while (<DATA>) {
my ($col3) = (split)[-1];
print if !$seen{$col3}++ or !$col3;
}
__DATA__
chr1 12226559 12227059 TNFRSF1B
chr1 17051560 17052060
chr1 17053279 17053779
chr1 17338423 17338923 ATP13A2
ATP13A2
ATP13A2
chr1 19577574 19578074 EMC1
MRTO4
chr1 19578046 19578546 EMC1
MRTO4
chr1 19638239 19638739 AKR7A2
PQLC2
PQLC2
PQLC2
输出:
chr1 12226559 12227059 TNFRSF1B
chr1 17051560 17052060
chr1 17053279 17053779
chr1 17338423 17338923 ATP13A2
chr1 19577574 19578074 EMC1
MRTO4
chr1 19638239 19638739 AKR7A2
PQLC2
此输出也可以通过以下单行实现:
perl -ane "print if !$X{$F[-1]}++ or !$F[-1]" data.txt
使用一个小perl
脚本:
perl -e 'my $col4 = "";
while (<>) {
chomp;
my @f = split(/t/, $_);
if ($f[3] eq "" || $f[3] ne $col4) {
print $_, "n";
}
$col4 = $f[3];
}' input.txt
结果:
chr1 12226559 12227059 TNFRSF1B
chr1 17051560 17052060
chr1 17053279 17053779
chr1 17338423 17338923 ATP13A2
chr1 19577574 19578074 EMC1
MRTO4
chr1 19578046 19578546 EMC1
MRTO4
chr1 19638239 19638739 AKR7A2
PQLC2
<</div>
div class="one_answers"> 鉴于新发布的输入,我会使用:
gawk -F't' '!/^t/{delete a} !a[$4]++' file
我使用 gawk,所以我可以一次清楚地删除整个数组,而其他 awk 使用不太清楚的:
awk -F't' '!/^t/{split("",a)} !a[$4]++' file
如果重复的行在所有列中都是重复的,而不仅仅是第四列,uniq(1) 可能是合适的。尝试只运行uniq file
,看看输出是否是您所期望的。