awk: So trennen Sie alle Zeilen mit demselben Inhalt in einer bestimmten Spalte in verschiedenen Dateien

awk: So trennen Sie alle Zeilen mit demselben Inhalt in einer bestimmten Spalte in verschiedenen Dateien

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:

  1. Einige Awks erfordern Klammern um einen Ausdruck auf der rechten Seite der Ausgabeumleitung und
  2. 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
  3. das Offenhalten mehrerer Ausgabedateien ist in allen Awks, die dies zulassen, sehr ineffizient, und
  4. 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.csvusw. file_B.csvBeachten 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, -Fdient 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

verwandte Informationen