
Ich habe eine große CSV-Datei (Test.csv), die so aussieht:
1,2,3,A,5
1,2,3,B,5
1,2,3,E,5
1,2,3,D,5
1,2,3,Z,5
1,2,3,B,5
Ich möchte die Zeilen, deren 4. Spalte den gleichen Inhalt hat, in verschiedenen Dateien drucken. Eigentlich muss ich diese Zeilen mit gleichem Inhalt in einer neuen CSV- oder TXT-Datei zusammenführen, die den Namen „Inhalt der 4. Spalte“ trägt. Beispiel:
Ausgabe:
Datei A
1,2,3,A,5
1,2,3,A,5
1,2,3,A,5
Datei B
1,2,3,B,5
1,2,3,B,5
Da die Eingabedatei groß ist, habe ich keine Ahnung, wie viele verschiedene Muster es in dieser 4. Spalte gibt. Spalte 4 enthält nur Wörter und die anderen Spalten enthalten Wörter und/oder Zahlen.
Da ich keine Erfahrung habe, habe ich ähnliche Fragen untersucht und sogar den folgenden Code ausprobiert:
awk 'NR==FNR{a[$4]=NR; next} $NF in a {print > "outfile" a[$NF]}' Test.csv
aber nichts hat funktioniert. Kann mir bitte jemand helfen? Vielen Dank im Voraus.
Antwort1
Dies funktioniert effizient mit POSIX sort und jedem awk in jeder Shell auf jeder UNIX-Box:
$ sort -t, -k4,4 test.csv |
awk -F, '$4!=prev{close(out); out="File"$4; prev=$4} {print > out}'
$ head -n 20 File*
==> FileA <==
1,2,3,A,5
==> FileB <==
1,2,3,B,5
1,2,3,B,5
==> FileD <==
1,2,3,D,5
==> FileE <==
1,2,3,E,5
==> FileZ <==
1,2,3,Z,5
Einige Dinge, die Sie beachten sollten:
- Einige Awks erfordern Klammern um einen Ausdruck auf der rechten Seite der Ausgabeumleitung und
- einige Awks schlagen fehl, wenn Sie die Ausgabedateien nicht schließen, während sie laufen, und versuchen daher, zu viele offene Dateien zu behalten, wenn sie mehr als ein Dutzend Ausgabedateien haben, und
- das Offenhalten mehrerer Ausgabedateien ist in allen Awks, die dies zulassen, sehr ineffizient, und
- Das zeilenweise Schließen von Ausgabedateien, um dies zu berücksichtigen, wäre in allen AWKs sehr ineffizient.
Antwort2
Sie sollten das Feld einfach im Ausgabedateinamen verwenden können. Eine einfache Lösung:
awk -F, '{print > ("file_" $4 ".csv")}' Test.csv
Dies funktioniert zumindest in GNU awk und erstellt file_A.csv
usw. file_B.csv
Beachten Sie, dass hierbei alle Ausgabedateien geöffnet bleiben und es langsamer wird, je mehr Dateien es gibt, insbesondere wenn Sie das Limit für die pro Prozess geöffneten Dateien erreichen.
-F,
Setzt das Komma als Feldtrennzeichen.
Ich bin nicht sicher, was das von Ihnen gezeigte Skript tun soll.
Antwort3
Etwas wie das:
$ awk -F, '{ print $0 >> "file-" $4 ".txt"; }' ./tmp.txt
Wie in der Antwort von @ilkkachu erwähnt, -F
dient Flag dazu, den Feldtrenner von den standardmäßigen Leerzeichen in ein Komma zu ändern. Sie sollten
>>
stattdessen verwenden >
, damit Sie die Datei nicht überschreiben, falls sie vorhanden ist.
Antwort4
Python
#!/usr/bin/python
uni=[]
k=open('file.txt','r')
for i in k:
g=i.split(",")[3].strip()
if g not in uni:
uni.append(g)
for m in uni:
f=open("{0}.txt".format(m),'w')
l=open('file.txt','r')
for d in l:
if m in d.split(",")[3].strip():
f.write(d)
Die beste Lösung, die in awk bereits zur Verfügung steht, ist nur mein Versuch
for i in `awk -F "," '{if(!seen[$4]++)print $4}' file.txt`; do awk -v i="$i" -F "," '$4==i{print $0}' file.txt >$i.txt; done