Ich habe eine CSV-Datei (auf einem Mac), die eine Reihe von Leerzeilen enthält, z.
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum
lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum
lorem ipsum ","2","3","4"
Was ich konvertieren möchte:
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
"1", "2", "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum ","2","3","4"
Ich weiß, dass es einen Einzeiler geben muss, aber ich weiß nicht, ob awk oder sed. Irgendwelche Tipps sehr geschätzt!
shell
text-processing
sed
awk
Pitosalas
quelle
quelle
Antworten:
Sie können dazu den Grep-
-v
Modus (Invert Match) verwenden:Beachten Sie, dass dies unterschiedliche Dateien sein müssen, da Shell-Weiterleitungen funktionieren. Die Ausgabedatei wird geöffnet (und geleert), bevor die Eingabedatei gelesen wird. Wenn Sie mehr Utils haben (nicht standardmäßig unter Mac OS X), können Sie dies umgehen
sponge
:Aber dann fällt es Ihnen natürlich schwerer, zurück zu gehen, wenn etwas schief geht.
Wenn Sie "Leerzeilen" tatsächlich Leerzeichen enthalten können (es hört sich so an), können Sie dies stattdessen verwenden:
Dadurch werden Leerzeilen sowie Zeilen, die nur Leerzeichen enthalten, ignoriert. Sie können natürlich die gleiche
sponge
Transformation durchführen.quelle
egrep -v '^[[:space:]]*$'
... beachten Sie grep -> egrep und das seltsame neue Mustericonv -f utf16le file.csv | head
odericonv -f utf16be file.csv | head
Die einfachste Option ist nur
grep .
. Hier bedeutet der Punkt "Alles abgleichen". Wenn die Zeile leer ist, stimmt sie nicht überein. Andernfalls wird die gesamte Zeile so gedruckt, wie sie ist.quelle
So entfernen Sie leere Zeilen, an Ort und Stelle , mit ksh93:
Der
<>;
Umleitungsoperator ist spezifisch für ksh93 und entspricht dem Standardoperator<>
, außer dass ksh die Datei nach Beendigung des Befehls abschneidet.sed '/./!d'
ist eine verschlungene Schreibweisegrep .
, aber leider beschwert sich GNU grep zumindest, wenn sein stdout auf dieselbe Datei verweist wie sein stdin. Man könnte sagen, man könnte schreiben:Leider gibt es in ksh93 (zumindest in meiner Version (93u +)) einen Fehler, da die Datei in diesem Fall auf die Länge Null abgeschnitten zu sein scheint.
Scheint diesen Fehler zu umgehen, aber jetzt ist er weitaus komplizierter als der Befehl sed.
quelle
awk '/./' file 1<>; file
was funktioniert hat. Für mich ist das noch klarer alssed '/./!d'
Hier ist ein
Perl
Einzeiler dafür:BEARBEITEN: Verbesserter Code basierend auf den Kommentaren von ruakh unten.
quelle
perl -ni -e '/./ and print' yourfile
$
ist ein Anker (dh eine Breite von Null), daher wird die neue Zeile ausgeschlossen. Was den überflüssigen Raum betrifft, so habe ich hinzugefügt, dass/x
ich nichtPerl
versuchen wollte , "$" in den regulären Ausdruck zu interpolieren$
, vorausgesetzt, Sie haben das\n
. (Alternativ - Sie brauchen das nicht , vorausgesetzt\n
, Sie haben das\s*
und das$
; aber ich denke, ess/^\s*\n//
macht klarer, dass die neue Zeile entfernt wird.) Sie brauchen das auch nicht/m
; Dies hat keine Auswirkung auf diesen Befehl. Und wenn Sie den$
und den Raum loswerden , brauchen Sie den nicht mehr/x
.\n
selbst kann entfernt werden; Was Sie nicht tun können, ist sowohl das$
als auch das zu entfernen\n
. Hättes/^\s*//
also das Problem, das du beschreibst,s/^\s*$//
wäre aber wegen dem\s*
und dem in Ordnung$
. (Sehen Sie, was ich meine?)$
kann vor einer neuen Zeile übereinstimmen (vorausgesetzt, dass entweder das/m
Flag aktiviert ist oder die neue Zeile das allerletzte Zeichen der Zeichenfolge ist oder beides), aber es kann auch mit dem Ende der Zeichenfolge übereinstimmen. Zum Beispiel"abc" =~ m/^abc$/
ist wahr. Im Fall von\s*$
ist das\s*
gierig genug, um die neue Zeile zu verschlingen, und dann$
stimmt das mit dem Ende der Zeichenfolge überein. (Aber ich denke, ess/^\s*\n//
ist sowieso klarer, so dass Ihre Antwort in Ordnung ist, wie es jetzt ist.)Basierend auf der Klarstellung in den Kommentaren zu Ihrer Frage, etwas wie:
kann tun, was Sie wollen.
Ein leeres Datensatztrennzeichen ist ein Sonderfall, der besagt,
awk
dass Datensätze Absätze sein sollen (durch Leerzeichenfolgen getrennt). Wenn Sie auch das Trennzeichen für den Ausgabedatensatz auf die leere Zeichenfolge setzen, muss der Inhalt dieser Absätze (ohne Trennzeichen) verkettet werden.1
ist nur eine wahre Bedingung, um jeden Datensatz zu drucken.Das würde jedoch die nachfolgende Newline weglassen, so dass Sie Folgendes tun könnten:
quelle
Ich weiß, dass dies einfacher gewesen wäre, wenn ich die Datei gegeben hätte, aber leider enthielt sie vertrauliche Informationen, die ich nicht teilen konnte. In der Zwischenzeit schrieb ich mir ein Ruby-Skript, das den Trick zu tun schien:
Vielen Dank an alle für ihre Hilfe!
quelle
produziert
quelle
Ich habe eine Idee für eine mögliche Lösung für den Stackoverflow gefunden .
sed -i ':a;N;$!ba;s/[^"]\n\s*\n/ /g' file.csv
Sie sollten Ihre CSV-Datei wahrscheinlich sichern, bevor Sie sie testen, aber zumindest für das Beispiel, das Sie angegeben haben, funktioniert sie einwandfrei.
Eine gute Erklärung für das Innenleben dieses Ausdrucks finden Sie in der Antwort. Ich habe ihn nur bearbeitet, um nach Zeilen zu suchen, die nicht mit einem
"
([^"]\n
) enden .quelle
Wenn Sie aus Ihrer eigenen Antwort Zeilenumbruchzeichen in Anführungszeichen entfernen möchten, haben Sie folgende Möglichkeiten:
Sie könnten auch die Verwendung von Perl verwenden
-i
Flagge zu bearbeiten die Dateien an Ort und Stelle .Oder mit GNU awk:
oder:
(wenn Sie um den kürzesten konkurrieren)
Beachten Sie, dass diejenigen annehmen , dass es kein entkommen doppelte Anführungszeichen in der Eingabe.
quelle
Es sieht so aus, als ob Sie mehr wollen als nur leere Zeilen zu entfernen, sondern jede Folge von 2 oder mehr Zeilenumbrüchen entfernen.
Was du mit Perl machen könntest:
Sie könnten auch die Verwendung von Perl verwenden
-i
Flagge zu bearbeiten die Dateien an Ort und Stelle .quelle
Es gibt eine immer kürzere Möglichkeit, leere Zeilen zu entfernen
AWK
:awk 'NF' file
Aber um die gewünschte Ausgabe zu erhalten, ist lediglich ein einfacher Einzeiler erforderlich:
awk 'NF {printf("%s ", $0); i++;} !(i % 2) {printf("\n");}' file
Erläuterung
In
AWK
bedeutet eine leere Zeile, dass die Zeile / der Datensatz keine Felder enthält,NF
dh die Variable (Anzahl der Felder) ist Null. Der eine Liner oben wird nur ausgeführt, wennNF > 0
alle Zeilen gedruckt werden, aber die leeren.Das
i++
ist der Zähler für nicht leere Zeilen.Das
!(i % 2)
wird verwendet, um zwei aufeinanderfolgende nicht leere Zeilen auf die Weise Ihrer gewünschten Ausgabe zu drucken, dh jedes Mal, wenn ein Vielfaches von 2 gefunden wird, ergibt diemodulo
Anweisung!(i % 2)
1, was die Verkettung von zwei nicht leeren Zeilen beendet.quelle
Sie können Vim im Ex-Modus verwenden:
v/./
finde leere Zeilend
löschenx
speichern und schließenquelle