CSV-Datei mit sed umwandeln

5296
middus

Um einige Daten in ein bestimmtes Tool importieren zu können, muss ich eine CSV-Datei aus diesem Format konvertieren

"data","data","data data","data","123" 

in dieses Format

data;data;data data;data;123 

Die Spalten enthalten nie ", ;oder ,aber es können Räume. Zur Zeit verwende ich folgendes

sed -e 's/","/;/g' -e 's/"//g' input.csv > output.csv 

Obwohl dies gut funktioniert, frage ich mich, ob dies eleganter gemacht werden kann, dh

  • Ist sed das richtige Werkzeug (Standard Unix) für den Job?
  • Wäre es möglich, beide Ausdrücke zu einem zusammenzuführen?

Danke für deinen Beitrag!

7

3 Antworten auf die Frage

6
ayrnieu
( tr, ';' | tr -d '"' ) < input.csv > output.csv 

Ich würde Perl verwenden

perl -pe 'tr/,"/;/d' input.csv > output.csv 

- aber diese spezifische Aufgabe ist nicht mehr als sed. Sie können die beiden Ausdrücke nicht zusammenführen.

Danke für Ihre Antwort, IMHO zwei schöne Lösungen. Könnten Sie das erklären? in der mit tr? Es ist nicht dasselbe wie [: punct:], richtig? mann tr hilft mir nicht. Es scheint eine Frage des Geschmacks zu sein, welche Antwort die beste ist. Wenn die Autoren der anderen Antworten keine Einwände erheben, werde ich diese als akzeptierte Antwort festlegen, da sie für mich sehr elegant aussieht und die Community sie bisher als die höchste bewertet hat. middus vor 14 Jahren 0
es macht mir nichts aus Ich bin selbst ein Teil der Perl-Version. Perls tr Felsen. quack quixote vor 14 Jahren 0
Sorry - das sollte sein, ayrnieu vor 14 Jahren 0
5
quack quixote

Was Sie bevorzugen (perl, sed, awk), liegt bei Ihnen. Sie werden alle die Arbeit erledigen. Da Sie nach Sed gefragt haben und die anderen gepostet werden, geht es los. Dies ist eine einfachere Form Ihrer regulären Ausdrücke und funktioniert mit Ihrer Beispielzeile:

$ sed -e 's/"//g; s/,/;/g' infile.csv > outfile.csv 

Beachten Sie können die beiden Ausdrücke mit einem Semikolon nach jeder Substitution verbinden. Getestet mit GNU sed v4.1.5.

Hier sind Ihre ursprünglichen Ausdrücke:

$ sed -e 's/","/;/g; s/"//g' infile.csv > outfile.csv 

Ich bin ziemlich sicher, dass es möglich ist, die beiden Substitutionen zusammenzuführen. Ich bin mir nicht sicher, was es wäre, und ich bin mir ziemlich sicher, dass das Ergebnis viel weniger lesbar sein wird als das Skript an der Spitze. Wenn mir etwas einfällt (oder jemand anderes wiegt in den Kommentaren), füge ich es hier hinzu.

"Sie können sich ** den beiden Unterwahlen anschließen" - Sie können nicht. Sie haben zwei Ausdrücke genommen und sie durch zwei Ausdrücke ersetzt. ayrnieu vor 14 Jahren 0
Sein Original war "-e" foo "-e" bar "", ich verband sie mit "-e" foo; bar "". Das -e ist der Ausdruck, auf den ich mich beziehe, und nahm an, dass er sich darauf bezog. Sie haben vielleicht recht - ich habe falsch verstanden, wonach er verlangt -, aber Sie verstehen auch meine Aussage falsch. quack quixote vor 14 Jahren 0
geklärt. Ich hoffe. :) quack quixote vor 14 Jahren 0
Das ist cool, ich wusste nicht, dass man solche Ausdrücke einfach verbinden könnte. Danke für deine Antwort! middus vor 14 Jahren 0
4
wfaulk

Da Sie mit Datensätzen zu tun haben, awkist es sinnvoller. Das heißt, es ist bei CSV nicht wirklich gut, da die Feldtrenner etwas variabel sind. Wenn Sie jedoch sicher sind, dass alle Felder in doppelte Anführungszeichen gesetzt sind, funktioniert dies:

awk -F'","' 'BEGIN { gsub(/(^")|("$)/, ""); $1=$1; print }' 

Dies setzt das Eingabefeldtrennzeichen von awk auf " ","" (einschließlich der inneren Anführungszeichen). Dies funktioniert fast, außer dass Sie sich mit den führenden und nachgestellten doppelten Anführungszeichen befassen müssen, die mit der gsubFunktion entfernt werden. Das $1=$1zwingt ihn, den Datensatz mit dem neuen Ausgabefeld-Trennzeichen neu zu kompilieren, das wie ;im BEGIN-Block definiert wurde. Dann printwird der gesamte Datensatz ausgedruckt.

Das ist ein bisschen sauberer:

awk -F '(^")|(",")|("$)' 'BEGIN { $1=$1; print }' 

Das Eingabefeldtrennzeichen wird auf einen regulären Ausdruck gesetzt, der die doppelten Anführungszeichen am Anfang und am Ende des Datensatzes enthält. Es wird jedoch auch ein leeres Anfangs- und Nachlauffeld ausgegeben. Sie können das nachfolgende Feld leicht loswerden:

awk -F '(^")|(",")|("$)' 'BEGIN { NF=NF-1; $1=$1; print }' 

NFist die Anzahl der Felder und die Reduzierung um eine Stelle vom letzten Feld. Aber ich kann mir keine Möglichkeit vorstellen, das erste Feld abzuschneiden.

Wenn Sie wissen, dass die Eingabe immer fünf Felder enthält, können Sie Folgendes tun:

awk -F '(^")|(",")|("$)' 'BEGIN { print $2,$3,$4,$5,$6 }' 

Beachten Sie, dass dadurch das $1=$1Konstrukt entfernt wird, das wir nur brauchen, wenn wir die (implizierten) $ 0 drucken.

Alles in allem würde ich wahrscheinlich Perl und eines der vielen verfügbaren CSV-Module für CPAN verwenden .

Okay, das sieht etwas komplexer aus als die anderen Lösungen und ist nicht zu lesbar. Wenn ich in einem Jahr darauf stoßen würde, müsste ich mich wahrscheinlich fragen, was es bewirkt. Es ist jedoch schön zu sehen, dass mehrere verschiedene Tools (awk, sed ...) für die Aufgabe geeignet sind. Vielen Dank für Ihre ausführliche Antwort. Ich nehme es als Einstiegspunkt, um in awk nach anderen Problemen zu suchen. middus vor 14 Jahren 0
es sieht schlimmer aus als es ist. Sobald Sie anfangen, etwas zu lernen, wird es einfacher zu lesen. :) quack quixote vor 14 Jahren 0
Es ist komplexer, weil es intelligenter ist und versucht, Datensätze als Datensätze zu behandeln, anstatt Zeichenfolgen, die wie CSV aussehen, als Zeichenfolgen. Dies leidet unter einer weniger komplexen Komplexitätswand - ein Punkt, an dem eine kleine Ergänzung der Problembeschreibung eine enorme Änderung in der Lösung bewirkt (z. B. die gesamte Lösung wegwerfen und eine andere von Grund auf neu erstellen). ayrnieu vor 14 Jahren 0