2010-03-29 7 views
36

Ich habe eine Tab-getrennte Datei, die über 200 Millionen Zeilen hat. Was ist der schnellste Weg in Linux, um dies in eine CSV-Datei zu konvertieren? Diese Datei enthält mehrere Zeilen mit Kopfzeileninformationen, die ich im Laufe der Zeit entfernen muss, aber die Anzahl der Kopfzeilen ist bekannt. Ich habe Vorschläge für sed und gawk gesehen, aber ich frage mich, ob es eine "bevorzugte" Wahl gibt.schnellste Weg Tab-getrennte Datei in CSV in Linux konvertieren

Zur Klarstellung, es gibt keine eingebetteten Registerkarten in dieser Datei.

+0

Für csv tsv und eingebettete Begrenzer Probleme finden Sie auch Antworten auf http://stackoverflow.com/questions/13475535/replace-every-comma-not-enclosed-in-a-pair-of-double -quotes-with (auch relevant: http://unix.stackexchange.com/questions/48672/remove-common-between-the-quotes-only-in-a-comma-delimited-file). –

Antwort

38

Wenn alles, was Sie tun müssen, ist übersetzen alle Tab-Zeichen zu Komma-Zeichen, tr ist wahrscheinlich der Weg zu gehen.

Der leere Raum hier ist eine wörtliche tab:

$ echo "hello world" | tr "\\t" "," 
hello,world 

Natürlich, wenn Sie Registerkarten innerhalb Stringliterale in der Datei eingebettet sind, das diese ebenfalls falsch übersetzen wird; eingebettete Literalregister wären jedoch ziemlich unüblich.

+13

Häufiger sind eingebettete Kommas in der Quelle, die dann in Anführungszeichen eingeschlossen werden müssen. Was ärgerlich ist, wenn es eingebettete Zitate gibt ... – kibibu

+0

Danke für den 'tr' Vorschlag. Wie vergleicht es sich mit "sed" mit Geschwindigkeit? Angenommen, Sie wollten den Headeranfang unter der Zeilennummer x überspringen und mit dem Rest der Datei fortfahren. Gibt es eine Möglichkeit, dies mit "tr" zu implementieren? (Ich sollte auch klarstellen, dass es in der Datei keine eingebetteten Kommas gibt.) – andrewj

+0

@andrewj: 'tr' sollte viel schneller sein, da es nur Zeichen-zu-Zeichen-Ersetzen anstelle von Regex-Übereinstimmung gibt. Was das Überspringen von Kopfzeilen betrifft, ist es am einfachsten, nur zwei Abschnitte zu verarbeiten - wenn Sie die Länge kennen, 'head -n input> output; tail -n + Eingabe | tr ... >> Ausgabe'; wenn du die Länge nicht kennst, wahrscheinlich etwas mit 'grep -n' ... – Cascabel

62

Wenn Sie über eingebettete Kommas besorgt sind, dann müssen Sie eine etwas intelligentere Methode verwenden. Hier ist ein Python-Skript, das TSV Zeilen von stdin nimmt und schreibt CSV Zeilen an stdout:

import sys 
import csv 

tabin = csv.reader(sys.stdin, dialect=csv.excel_tab) 
commaout = csv.writer(sys.stdout, dialect=csv.excel) 
for row in tabin: 
    commaout.writerow(row) 

Run es von einem Shell wie folgt:

python script.py <input.tsv> output.csv 
+1

Wenn Sie nicht sicher sind, dass keine eingebetteten Kommas und keine eingebetteten Registerkarten vorhanden sind, ist dies eine sehr zuverlässige Methode. Auch wenn es wahrscheinlich nicht die Kriterien erfüllt, um "der Schnellste" zu sein. – leedm777

+2

Es ist vielleicht nicht "die schnellste", aber es behandelt eingebettete Tabs und Kommas für mich. – anshuman

+1

Das rockt. Ich habe ein kryptisches sed-Skript geschrieben, um das in bash zu erledigen - aber das kann nicht mit der Vollständigkeit der Python-CSV-Bibliothek konkurrieren. Danke Ignacio, für dieses Angebot. In Bezug auf Geschwindigkeit - Benutzerfreundlichkeit und Zuverlässigkeit - Geschwindigkeit ist sicher schnell genug. :-) – dlink

3

vorausgesetzt, Sie nicht Header ändern möchten, und unter der Annahme, Sie haben keine eingebetteten Registerkarten

NR> 1 überspringt den ersten Header. Sie haben erwähnt, dass Sie wissen, wie viele Zeilen des Headers Sie verwenden, also verwenden Sie die richtige Nummer für Ihren eigenen Fall. damit müssen Sie auch keine anderen externen Befehle aufrufen. nur ein awk Befehl macht den Job.

ein anderer Weg, wenn Sie leere Spalten haben und Sie sich darum kümmern.

awk 'NR>1{gsub("\t",",")}1' file 

unter Verwendung von sed

sed '2,$y/\t/,/' file #skip 1 line header and translate (same as tr) 
6
sed -e 's/"/\\"/g' -e 's/<tab>/","/g' -e 's/^/"/' -e 's/$/"/' infile > outfile 

Verdammt die Kritiker, Zitat alles, ist CSV nicht.

<tab> ist das eigentliche Tab-Zeichen. Es hat nicht für mich funktioniert. In bash, benutze^V, um es einzugeben.

+0

For Tab, Sie können 'sed -e '/"/\\ "/ g' -e" s/\ t/\ ", \"/g "-e 's/^ /" /' -e 's tun/$/"/ 'infile> outfile". –

15
perl -lpe 's/"/""/g; s/^|$/"/g; s/\t/","/g' <input.tab> output.csv 

Perl ist in der Regel schneller bei dieser Art von Sache als die Sed, Awk und Python.

+1

beste antwort für mich, nur eine leicht ändern, scape doppelte anführungszeichen: perl -lpe' s/"/ \\"/g; s/^ | $/"/ g; s/\ t/","/g '<... – Lix

+0

lang lebe Perl! Genau der One-Liner, den ich brauchte. – Debriter

+0

Du bist ein Retter – Yankee

0

folgende awk oneliner unterstützt zitiert + quote-Flucht

printf "flop\tflap\"" | awk -F '\t' '{ gsub(/"/,"\"\"\"",$i); for(i = 1; i <= NF; i++) { printf "\"%s\"",$i; if(i < NF) printf "," }; printf "\n" }' 

gibt

"flop","flap"""" 
4

@ ignacio-Vazquez-Abrams ‚s Python Lösung groß ist! Für Personen, die andere Registerkarten mit Trennzeichen analysieren möchten, können Sie in der Bibliothek ein beliebiges Trennzeichen festlegen.Hier ist meine modifizierte Version Rohr getrennte Dateien zu handhaben:

import sys 
import csv 

pipein = csv.reader(sys.stdin, delimiter='|') 
commaout = csv.writer(sys.stdout, dialect=csv.excel) 
for row in pipein: 
    commaout.writerow(row) 
4
  • Wenn Sie die ganze tsv-Datei in eine CSV-Datei umwandeln möchten:

    $ cat data.tsv | tr "\\t" "," > data.csv 
    

  • Wenn Sie möchten, um einige Felder wegzulassen:

    $ cat data.tsv | cut -f1,2,3 | tr "\\t" "," > data.csv 
    

    Die Der obige Befehl konvertiert die Datei "data.tsv" in die Datei "data.csv" , die nur die ersten drei Felder enthält.

+1

sehr gut eins :) –

Verwandte Themen