
我仍在學習編程,並且嘗試了很多方法,但無法獲得正確的格式。我有一個製表符分隔文件有 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 下,等等。 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