我想知道是否有任何sed
命令awk
可以对具有相同标识符的行的所有列进行求和。例如,我的文件data.txt
如下所示,但它包含约 1800 列数据和约 1400 行。
ABCD:1234 1.23 0.23 0.83 0
ABCD:1234 0 1.10 0.21 0
EFGH:5678 0 1.90 0.12 8.21
IJKL:9999 1.22 0 1.84 9.21
IJKL:9999 1.44 0 12.94 0
IJKL:9999 1.32 0 24.12 2.43
我希望命令之后的样子是这样的:
ABCD:1234 1.23 1.33 1.04 0
EFGH:5678 0 1.90 0.12 8.21
IJKL:9999 3.98 0 38.9 11.64
我不确定这是否可以用awk
or sed
(我是一名生物学家,仍在学习 Unix 的基础知识)。任何帮助将非常感激。
答案1
awk
不将输入文件或整个结果表保存在内存中的脚本:
FNR == 1 { for(i = 1; i <= NF; i++) a[i] = $i; next }
$1 == a[1] { for(i = 2; i <= NF; i++) a[i] += $i; next }
{
printf "%s", a[1]; a[1] = $1;
for(i = 2; i <= NF; i++) { printf "\t%s", a[i]; a[i] = $i };
printf "\n";
}
END {
printf "%s", a[1];
for(i = 2; i <= NF; i++) printf "\t%s", a[i];
printf "\n";
}
运行它:
awk -f script.awk data.txt
结果:
ABCD:1234 1.23 1.33 1.04 0
EFGH:5678 0 1.90 0.12 8.21
IJKL:9999 3.98 0 38.9 11.64
附带说明:实际上可以使用sed
.但你不会很快这样做。看这里了解原因。
答案2
替代解决方案perl
$ perl -nale '
if(!$seen{$F[0]}++)
{
print join "\t", @a if @a;
@a = @F[0..$#F];
}
else
{
$a[$_] += $F[$_] foreach(1..$#F);
}
print join "\t", @a if eof;
' data.txt
ABCD:1234 1.23 1.33 1.04 0
EFGH:5678 0 1.90 0.12 8.21
IJKL:9999 3.98 0 38.9 11.64
-a
按空格分割输入行并将它们保存到@F
数组中- 行的第一个字段用作哈希变量的键
%seen
,如果未找到键,则打印@a
数组的内容(如果它不为空)并将新行的字段分配给数组 - 如果键已经存在,则将数组的内容(从第二个字段到末尾)增加到当前行中的相应内容
@a
要处理最后一个条目,请在到达文件末尾时再次打印数组内容
对于重复的问题:如果第一列有相同的条目,则在 Linux 中分别添加所有列
$ perl -nale '
if(!$seen{$F[0]}++)
{
print join "\t", @a if @a;
@a = @F[0..$#F];
}
else
{
$a[$_] += $F[$_] foreach(1..$#F);
}
print join "\t", @a if eof;
' filename.txt
AC1481523 6 6 6 6
AC1481676 6 5 6 8
构建数组哈希并在最后打印哈希的解决方案:
$ perl -nale '
if($h{$F[0]})
{
$h{$F[0]}[$_] += $F[$_] foreach (1..$#F)
}
else
{
$h{$F[0]} = [@F]
}
END { print join "\t",@{$h{$_}} foreach sort keys %h }
' data.txt
ABCD:1234 1.23 1.33 1.04 0
EFGH:5678 0 1.90 0.12 8.21
IJKL:9999 3.98 0 38.9 11.64