这是我第一次遇到这种情况。我需要为第一个字段做uniq,但没有删除重复行的任何内容。举个例子
输入文件
ENST000001.1 + 67208778 67210057
ENST000001.1 + 67208778 67210768
ENST000001.1 + 67208778 67208882
ENST000002.5 + 67208778 67213982
ENST000003.1 - 57463571 57463801
ENST000003.1 - 57476352 57476463
ENST000003.1 - 57476817 57476945
当我这样做(uniq -w 12)时,只会检查第一个字段(只有12个字符)的所有其他行的重复字段。结果将是这样的:
ENST000001.1 + 67208778 67210057
ENST000002.5 + 67208778 67213982
ENST000003.1 - 57463571 57463801
丢弃所有重复行的内容,仅保留第一行。我正在寻找的是这样的
ENST000001.1 + 67208778_67210057 67208778_67210768 67208778_67208882
ENST000002.5 + 67208778_67213982
ENST000003.1 - 57463571_57463801 57476352_57476463 57476817_57476945
如何在不丢失重复行内容的情况下使用uniq?有没有办法在AWK / sed / perl中执行此操作?
答案 0 :(得分:3)
awk '{a[$1" "$2]=a[$1" "$2]" "$3" "$4;}END{for(i in a)print i,a[i]}' your_file
测试如下:
> cat temp
ENST000001.1 + 67208778 67210057
ENST000001.1 + 67208778 67210768
ENST000001.1 + 67208778 67208882
ENST000002.5 + 67208778 67213982
ENST000003.1 - 57463571 57463801
ENST000003.1 - 57476352 57476463
ENST000003.1 - 57476817 57476945
> awk '{a[$1" "$2]=a[$1" "$2]" "$3" "$4;}END{for(i in a)print i,a[i]}' temp
ENST000002.5 + 67208778 67213982
ENST000003.1 - 57463571 57463801 57476352 57476463 57476817 57476945
ENST000001.1 + 67208778 67210057 67208778 67210768 67208778 67208882
如果您具体使用下划线(_
),请使用以下内容:
> awk '{a[$1" "$2]=a[$1" "$2]" "$3"_"$4;}END{for(i in a)print i,a[i]}' temp
ENST000002.5 + 67208778_67213982
ENST000003.1 - 57463571_57463801 57476352_57476463 57476817_57476945
ENST000001.1 + 67208778_67210057 67208778_67210768 67208778_67208882
>
说明:
- >创建一个关联数组a,其键将是第一个字段+空格+第二个字段。
- >每个键的值是其前一个值+第三个字段+下划线+第四个字段
- >在处理完所有行之后执行结束块。并且为了循环wiill循环遍历ass..array并打印其键和值。
由于perl也被标记,这里是perl解决方案:
perl -F -lane '$H{$F[0]." ".$F[1]}=$H{$F[0]." ".$F[1]}." ".$F[2]."_".$F[3];if(eof){foreach(keys %H){print $_,$H{$_}}}' your_file
上面的perl解决方案适用于命令行本身。
答案 1 :(得分:1)
在Perl中,您可以通过将它们分组到hashref中来完成。
#!/usr/bin/perl
use strict;
use warnings;
my $lines;
while (<DATA>) {
chomp;
my @fields = split /\s+/;
push @{ $lines->{"$fields[0] $fields[1]"} }, "$fields[2]_$fields[3]";
}
foreach my $line (sort keys %$lines) {
print join("\t", $line, @{ $lines->{$line} }), "\n";
}
__DATA__
ENST000001.1 + 67208778 67210057
ENST000001.1 + 67208778 67210768
ENST000001.1 + 67208778 67208882
ENST000002.5 + 67208778 67213982
ENST000003.1 - 57463571 57463801
ENST000003.1 - 57476352 57476463
ENST000003.1 - 57476817 57476945
答案 2 :(得分:0)
这是一个Perl单行:
perl -lane 'BEGIN{$"=v9}push@{$u{"@F[0,1]"}},"$F[2]_$F[3]"}{while(($k,$v)=each%u){print"@{[$k,@$v]}"}'
扩展版本:
#!/usr/bin/env perl
use strict;
use warnings;
BEGIN { $/ = "\n"; $\ = "\n"; $" = "\t" }
my %u;
while (<ARGV>) {
chomp;
my @F = split /\s+/;
push @{$u{"@F[0, 1]"}}, "$F[2]_$F[3]";
}
while (my ($k, $v) = each %u) {
print "@{[$k, @$v]}";
}
答案 3 :(得分:0)
这可能适合你(GNU sed):
sed -r ':a;$!N;s/^((\S+\s+\S+).*)\n\2/\1/;ta;s/\<([0-9]+)\s+([0-9]+)\>/\1_\2/g;P;D' file