
Ich lerne noch Programmieren und habe schon vieles ausprobiert, aber ich bekomme einfach nicht das richtige Format hin. Ich habe eineTabulatorgetrenntDatei mit 17 Spalten und vielen (ca. 50.000) Zeilen. Die Datei ist bereits nach der ersten Spalte sortiert. Ich möchte Zeilen zusammenführen, die die gleiche erste Spalte (A) haben, aber alle anderen 16 Spalten sind unterschiedlich und ich möchte alle Informationen in einer Zeile behalten, vorzugsweise in der gleichen Spalte mitSemikolon ;als Trennzeichen zwischen ihnen. Ich möchte Tabulatoren als Trennzeichen in der Ausgabedatei beibehalten. Vielen Dank für die Antworten und wenn Sie auch die Antwort erklären könnten, wo ich einen Fehler gemacht habe, wäre das noch besser :).
Ich habe bisher versucht:
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
DATEIFORMAT (die anderen 15 Spalten haben das gleiche Format wie Spalte B)
A B C
123 fvv ggg
123 kjf ggg
123 ccd att
567 abc gst
567 abc hgt
879 ttt tyt
Die Ausgabe, die ich möchte (ich brauche alle 17 Spalten und für die Spalten 2-16 brauche ich dieselbe Ausgabe wie in Spalte B und C). Alle Fälle von B sollten unter B stehen und alle Fälle von C sollten unter C stehen und alle Fälle von D sollten unter D stehen usw. Die Ausgabe hat also genau wie die Eingabe 17 Spalten und statt 50.000 Zeilen sollte sie jetzt etwa 20.000 haben, da es viele Wiederholungen für Spalte 1 gibt (für diese bestimmte Datei):
A B C
123 fvv;kjf;ccd ggg;ggg;att
567 abc;abc gst;hgt
879 ttt lll
Antwort1
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]]
}
}'
Antwort2
Eine Perl-Lösung:
$ 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
Dies kann mit einer beliebigen Anzahl von Feldern funktionieren. Allerdings müssen dazu einige Dinge in den Speicher geladen werden, was bei großen Dateien ein Problem darstellen kann.
Was Ihren Fehler angeht, können wir Ihnen das nicht sagen, sofern Sie nicht erklären, was tatsächlich passiert ist. Aber spontan fällt mir ein, dass Ihr Perl-Versuch aus folgendem Grund fehlschlagen würde:
- Sie verwenden
-F,
, wodurch der Feldtrenner auf ein Komma gesetzt wird, wenn Ihre Eingabe Tabulatoren enthält. - Sie verwenden
-l
undprint "foo\n"
. Das-l
fügt bereits jedem Druckaufruf eine neue Zeile hinzu, sodass Sie mehrere leere Zeilen haben. - Sie verwenden
$h{$F[0]}.", ".$F[1];
zum Anhängen, sodass Sie beim ersten Ausführen, wenn es nicht definiert ist, am Anfang Ihres gespeicherten Werts$h{$F[0]}
ein zusätzliches Element hinzufügen .,
- Sie betrachten nur das zweite Feld und ignorieren alle anderen.
Ebenso awk
wird Ihr Versuch scheitern, weil:
- Sie drucken
foo""bar
, wodurch die Ausgabe ohne Leerzeichen zwischen den einzelnen Feldern aneinandergereiht wird. Sie möchtenprint foo,bar
und Sie möchten auchOFS="\t"
eine tabulatorgetrennte Ausgabe. - Sie betrachten nur das zweite Feld und ignorieren alle anderen.
Antwort3
entschuldigen Sie diesen Einzeiler, aber hier ist er -
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
Antwort4
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