Ich habe 4 TSV-Dateien (durch Tabulatoren getrennt), die so aussehen:
Datei_1:
abc 1
def 2
ghi 3
Datei_2:
abc 2
ghi 3
Datei_3:
def 1
ghi 2
jkl 4
Datei_4:
ghi 3
jkl 4
Ich möchte diese Dateien zusammenfügen, um eine TSV-Datei wie diese zu erhalten:
dataset file_1 file_2 file_3 file_4
abc 1 2
def 2 4
ghi 3 3 2 3
jkl 4 4
Ich habe versucht,awk
$ awk '
BEGIN{OFS=FS="\t"}
FNR==1{f = f "\t" FILENAME}
NR==FNR{a[$1] = $2}
NR!=FNR{a[$1] = a[$1] "\t" $2}
END{printf "dataset%s\n", f; for(i in a) print i, a[i]}
' file_{1..4}
Dieser Befehl funktioniert, aber ich habe einen verschobenen Wert erhalten. Angenommen, die erste und zweite Spalte haben einen leeren Wert und die dritte und vierte Spalte haben die Werte 4 und 4. Die Ausgabe, die ich von diesem Befehl erhalte, ist, dass die erste und zweite Spalte den Wert 4 haben, aber die dritte und vierte Spalte einen leeren Wert. Ich versuche also, meine TSV-Datei separat mit awk
dem von mir erwähnten zu verbinden. Zuerst nur für file_1
und file_2
um zu erhalten output_1
, dann verbinden file_3
und file_4
um zu erhalten output_2
. Danach verwende ich $ join output_1 output_2
zum Zusammenführen von Ausgabe_1 und Ausgabe_2, aber ich erhalte nur Werte, die in 4 Dateien vorhanden sind. Ich habe Daten verloren, die nur in einer Datei vorhanden sind.
Ich wäre Ihnen sehr dankbar, wenn Sie mir einen Rat geben könnten.
Danke
Antwort1
$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ datasets[$1]; fnames[FILENAME]; vals[$1,FILENAME] = $2 }
END {
printf "%s", "dataset"
for (fname in fnames) {
printf "%s%s", OFS, fname
}
print ""
for (dataset in datasets) {
printf "%s", dataset
for (fname in fnames) {
printf "%s%s", OFS, vals[dataset,fname]
}
print ""
}
}
$ tail -n +1 file?
==> file1 <==
a 1
b 2
c 3
==> file2 <==
a 2
c 3
$ awk -f tst.awk file1 file2
dataset file1 file2
a 1 2
b 2
c 3 3
Fügen Sie der Liste so viele Dateien hinzu, wie Sie möchten.
Antwort2
Mit join (GNU coreutils) 8.30
und "Prozesssubstitution" können Sie versuchen,
join -a1 -a2 -t" " -oauto -e " " <(join -a1 -a2 -t" " -oauto -e "" file[12]) <(join -a1 -a2 -t" " -oauto -e " " file[34])
abc 1 2
def 2 1
ghi 3 3 2 3
jkl 4 4
Die -t
Optionen haben einen <TAB>
Zeichenwert.
Antwort3
Tipp für jetzt: Code für später, falls Sie ihn brauchen.
Ich würde drei Arrays behalten, da Sie alle Dateien lesen.
(a) Für jede neue Datei eine Hash-Liste mit Dateinamen.
(b) Für jeden neuen Datensatz eine Hash-Liste mit $1.
(c) Für jede Zeile eine Hash-Liste mit Werten
FNR == 1 { ++htFile[FILENAME]; }
! ($1 in htSet) { ++htSet[$1]; }
{ htVal [FILENAME, $1] = $2; }
Iterieren Sie in einer End-Funktion über htFile und htSet.
function Table (r, c, buf) {
buf = "dataset";
for (c in htFile)
buf = sprint ("%s\t%s", buf, htFile[c]);
print buf;
for (r in htSet) {
buf = "";
for (c in htFile)
buf = sprint ("%s\t%s", buf, htVal[c, r]);
print substr (buf, 2);
}
}
END { Table( ); }
Dadurch wird die Reihenfolge der Dateien und Datensätze in der Ausgabetabelle nicht beibehalten. Wenn dies wichtig ist, können Sie eine sequenzierte Version der Tabellen beibehalten und in der ursprünglichen Reihenfolge iterieren.