Frage

Ich bin mit awk in der CSV-Datei Zählen der Summe einer Spalte auszuführen. Das Datenformat ist so etwas wie:

id, name, value
1, foo, 17
2, bar, 76
3, "I am the, question", 99

Ich war dieses awk-Skript unter Verwendung der Summe zu zählen:

awk -F, '{sum+=$3} END {print sum}'

Einige der Wert im Namensfeld enthält Komma und das ist mein awk Skript brechen. Meine Frage ist: kann awk dieses Problem lösen? Wenn ja, und wie kann ich das tun?

Danke.

War es hilfreich?

Lösung

schreiben Sie eine Funktion in awk wie unten:

$ awk 'func isnum(x){return(x==x+0)}BEGIN{print isnum("hello"),isnum("-42")}'
0 1

Sie können in Ihrem Skript übernehmen diese Funktion und prüfen, ob das dritte Feld ist numerisch oder NOT.IF nicht numerisch dann für das 4. Feld gehen und wenn das vierte Feld inturn nicht Numberic geht für 5. ist ... bis Sie ein erreichen numerischen value.probably eine Schleife wird hier helfen, und fügen sie ihn in der Summe.

Andere Tipps

Eine Möglichkeit, mit GNU awk und FPAT

awk 'BEGIN { FPAT = "([^, ]+)|(\"[^\"]+\")" } { sum+=$3 } END { print sum }' file.txt

Ergebnis:

192

Du bist besser wahrscheinlich off es in Perl mit Text zu tun :: CSV, da dies eine schnelle und robuste Lösung ist.

Sie können AWK Arbeit mit Datenfeldern helfen, die Kommas (oder Zeilenumbrüche) enthalten, die durch ein kleines Skript Ich rief csvquote schrieb. Er ersetzt die Kommas innerhalb zitierte Felder mit nicht druckbare Zeichen zu verletzen. Wenn Sie möchten, können Sie später diese Kommata wiederherstellen -. Aber in diesem Fall müssen Sie nicht auf

Hier ist der Befehl:

csvquote inputfile.csv | awk -F, '{sum+=$3} END {print sum}'

finden Sie unter https://github.com/dbro/csvquote für den Code

Ich bin mit

`FPAT="([^,]+)|(\"[^\"]+\")" `

die Felder mit gawk zu definieren. Ich fand, dass, wenn das Feld dieser null ist nicht korrekte Anzahl der Felder nicht erkennt. Da „+“ benötigt mindestens 1 Zeichen in dem Feld. Habe ich es zu:

`FPAT="([^,]*)|(\"[^\"]*\")"`

und ersetzen "+" mit "*". Es funktioniert richtig.

Ich finde auch, dass GNU Awk Benutzerhandbuch auch dieses Problem hat. https://www.gnu.org/software/gawk /manual/html_node/Splitting-By-Content.html

Für so einfach eine Eingabedatei als dass Sie nur eine kleine Funktion schreiben alle der realen FSs außerhalb der Zitate auf einen anderen Wert zu konvertieren (I RS gewählt, da die voneinander zu trennen sind nicht Teil des Datensatzes sein kann) und dann Verwendung dass als FS, zum Beispiel:

$ cat decsv.awk
BEGIN{ fs=FS; FS=RS }

{
   decsv()

   for (i=1;i<=NF;i++) {
       printf "Record %d, Field %d is <%s>\n" ,NR,i,$i
   }
   print ""
}

function decsv(         curr,head,tail)
{
   tail = $0
   while ( match(tail,/"[^"]+"/) ) {
       head = substr(tail, 1, RSTART-1);
       gsub(fs,RS,head)
       curr = curr head substr(tail, RSTART, RLENGTH)
       tail = substr(tail, RSTART + RLENGTH)
   }
   gsub(fs,RS,tail)
   $0 = curr tail
}

$ cat file
id, name, value
1, foo, 17
2, bar, 76
3, "I am the, question", 99

$ awk -F", " -f decsv.awk file
Record 1, Field 1 is <id>
Record 1, Field 2 is <name>
Record 1, Field 3 is <value>

Record 2, Field 1 is <1>
Record 2, Field 2 is <foo>
Record 2, Field 3 is <17>

Record 3, Field 1 is <2>
Record 3, Field 2 is <bar>
Record 3, Field 3 is <76>

Record 4, Field 1 is <3>
Record 4, Field 2 is <"I am the, question">
Record 4, Field 3 is <99>

Es wird nur kompliziert, wenn Sie mit eingebetteten Zeilenumbrüche und eingebettet entkam Anführungszeichen innerhalb der Anführungszeichen zu tun haben, und selbst dann ist es nicht zu hart und es ist alles getan worden, bevor ...

Siehe Was ist die robusteste Art und Weise zu effizient Parsing CSV mit awk? für weitere Informationen.

Sie können immer das Problem von der Quelle bekämpfen. Setzen Sie Anführungszeichen um das Namensfeld, genau wie das Feld von „Ich bin die, Frage“. Das ist viel einfacher, als Sie Ihre Zeit-Codierung Abhilfen für die Ausgaben.

Aktualisieren (als Dennis gewünscht). Ein einfaches Beispiel

$ s='id, "name1,name2", value 1, foo, 17 2, bar, 76 3, "I am the, question", 99'

$ echo $s|awk -F'"' '{ for(i=1;i<=NF;i+=2) print $i}'
id,
, value 1, foo, 17 2, bar, 76 3,
, 99

$ echo $s|awk -F'"' '{ for(i=2;i<=NF;i+=2) print $i}'
name1,name2
I am the, question

Wie Sie sehen können, indem Sie das Trennzeichen doppelte Anführungszeichen Einstellung, die Felder, die zu den „Anführungszeichen“ gehören, sind immer auf gerade Zahl ist. Da OP nicht über den Luxus der Quelldaten zu modifizieren, wird diese Methode nicht für ihn geeignet sein.

Wenn Sie sicher wissen, dass die ‚Wert‘ Spalte ist immer die letzte Spalte:

awk -F, '{sum+=$NF} END {print sum}'

NF steht für die Anzahl der Felder, so $ NF ist die letzte Spalte

Dieser Artikel geholfen hat mir dieses Feld Problem gleichen Daten zu lösen. Die meisten CSV wird ein Angebot um Felder mit Leerzeichen oder Komma in ihnen stecken. Diese Verwirrungen auf dem Posten für awk zählen, wenn Sie sie herausfiltern.

Wenn Sie die Daten in diesen Feldern müssen, die den Müll enthalten, dann ist dies nicht für Sie. ghostdog74 bereitgestellt, um die Antwort, die Leergut dieses Feld aber behält die Gesamtfeldzählung am Ende, welcher Schlüssel konsistent ist die Datenausgabe zu halten. Ich habe nicht so, wie diese Lösung neue Linien eingeführt. Dies ist die Version dieser Lösung, die ich verwenden. Die Faust drei Felder hatte nie dieses Problem in den Daten. Die vierten Feld mit Kundennamen oft, aber ich brauchte diese Daten. Die übrigen Felder, die das Problem aufweisen ich ohne Problem wegwerfen konnte, weil es nicht in meinem Bericht Ausgabe benötigt wurde. Also zuerst ich Sed aus dem Müll der 4. Feld sehr speziell und entfernen Sie die ersten zwei Instanzen von Anführungszeichen. Dann wende ich, was die restlichen Felder leeren ghostdog74gave, die Kommas in ihnen haben - dies beseitigt auch die Zitate, aber ich benutze printfto die Daten in einem einzigen Datensatz zu halten. Ich beginne mit 85 Feldern aus und mit 85 Feldern in allen Fällen von meinen 8000+ Linien unordentlich Daten landen. Ein perfektes Ergebnis!

grep -i $1 $dbfile | sed 's/\, Inc.//;s/, LLC.//;s/, LLC//;s/, Ltd.//;s/\"//;s/\"//' | awk -F'"' '{ for(i=1;i<=NF;i+=2) printf ($i);printf ("\n")}' > $tmpfile

Die Lösung, dass leert die Felder mit Kommas in ihnen aber auch den Rekord hält, natürlich ist:

awk -F'"' '{ for(i=1;i<=NF;i+=2) printf ($i);printf ("\n")}

Megs von dank ghostdog74 für die große Lösung!

NetsGuy256 /

FPAT ist die elegante Lösung, weil es die gefürchteten Kommas in Anführungszeichen Problem umgehen kann, aber eine Spalte von Zahlen in der letzten Spalte, unabhängig von der Anzahl der vorhergehenden Separatoren, $ NF funktioniert gut zusammenzufassen:

awk -F"," '{sum+=$NF} END {print sum}'

Um die vorletzte Spalte zuzugreifen, würden Sie verwenden:

awk -F"," '{sum+=$(NF-1)} END {print sum}'

vollwertiges CSV-Parser wie Perl Text::CSV_XS sind speziell gebaut, diese Art von Verrücktheit zu behandeln.

perl -MText::CSV_XS -lne 'BEGIN{$csv=Text::CSV_XS->new({allow_whitespace => 1})} if($csv->parse($_)){@f=$csv->fields();$sum+=$f[2]} END{print $sum}' file

allow_whitespace benötigt wird, da die Eingangsdaten Leerzeichen die Komma-Separatoren umgeben. Sehr alte Versionen von Text::CSV_XS können diese Option nicht unterstützen.

bereitgestellt ich mehr Erklärung von Text::CSV_XS in meiner Antwort hier: Parse-CSV-Datei gawk

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top