我仍在学习编程,并且尝试了很多方法,但无法获得正确的格式。我有一个制表符分隔文件有 17 列和许多(大约 50.000)行。该文件已按第一列排序。我想合并具有相同第一列 (A) 的行,但所有其他 16 列都不同,并且我想将所有信息保留在一行中,最好在同一列中分号 ;作为它们之间的分隔符。我想在输出文件中保留制表符作为分隔符。非常感谢您的回答,如果您也能解释我出错的地方,那就更好了:)。
到目前为止我已经尝试过:
awk -F'\t' 'NF>1{a[$1] = a[$1]";"$2}END{for(i in a){print i""a[i]}}' filename.txt
perl -F',' -anle 'next if /^$/;$h{$F[0]} = $h{$F[0]}.", ".$F[1];
END{print $_,$h{$_},"\n" for sort keys %h}' filename.txt
文件格式(其他 15 列与 B 列格式相同)
A B C
123 fvv ggg
123 kjf ggg
123 ccd att
567 abc gst
567 abc hgt
879 ttt tyt
我想要的输出(我需要所有 17 列,对于第 2-16 列,我需要与 B 列和 C 列相同的输出)。 B 的所有情况都应在 B 下,C 的所有情况应在 C 下,D 的所有情况应在 D 下,等等。因此,输出与输入一样有 17 列,而不是 50.000 行,现在应该有大约 20.000 行,因为第一列有很多重复(对于这个特定文件):
A B C
123 fvv;kjf;ccd ggg;ggg;att
567 abc;abc gst;hgt
879 ttt lll
答案1
awk '{
if(NR!=1){a[$1]=$2";"a[$1]}
else print $0}
END{
n = asorti(a, b);
for (n in b) {
print b[n],a[b[n]]
}
}'
答案2
Perl 解决方案:
$ perl -F"\t" -anle 'if($.==1){print; next} push @{$k{$F[0]}},@F[1..$#F];
END{print "$_\t" . join(";",@{$k{$_}}) for sort keys(%k)}' file
A B
123 fvv;kjf;ccd
567 abc;abc
879 ttt
这可以适用于任意数量的字段。但是,它确实需要将相当多的内容加载到内存中,如果您的文件很大,这可能会成为问题。
至于你哪里出错了,我们无法告诉你,除非你解释实际发生了什么,但是,在我的脑海中,你的 perl 尝试会失败,因为:
- 当您的输入有制表符时,您正在使用
-F,
它将字段分隔符设置为逗号。 - 您正在使用
-l
和print "foo\n"
。已经-l
为每个打印调用添加了一个换行符,因此您将有多个空白行。 - 您正在使用
$h{$F[0]}.", ".$F[1];
附加,因此第一次运行且未$h{$F[0]}
定义时,您将,
在存储值的开头添加一个额外的值。 - 您只查看第二个字段,忽略所有其他字段。
同样,你的意志awk
也会失败,因为:
- 您正在打印
foo""bar
,这将连接输出,每个字段之间没有空格。您想要print foo,bar
并且也想要OFS="\t"
制表符分隔的输出。 - 您只查看第二个字段,忽略所有其他字段。
答案3
为这一句抱歉,但事情是这样的——
awk 'BEGIN{FS="\t"} {for(i=2; i<=NF; i++) { if (!a[$1]) a[$1]=$1FS$i ;else a[$1]=a[$1]";"$i};if ($1 != old) b[j++] = a[old];old=$1 } END{for (i=0; i<j; i++) print b[i] }' 1
123 fvv ;kjf;ccd
567 abc;abc
879 ttt
答案4
awk '
function p(n,A){
s = n
for(i=2;i<=NF;i++){
s = s "\t" A[i]
A[i] = $i
}
if(n)
print s
}
NR==1{
print
next
}
$1==n{
for(i=2;i<=NR;i++)
A[i] = A[i] ";" $i
next
}
{
p(n,A)
n = $1
}
END{
p(n,A)
}
' file