Löschen Sie leere Zeilen mit sed


349

Ich versuche leere Zeilen mit sed zu löschen:

sed '/^$/d'

aber ich habe kein Glück damit.

Zum Beispiel habe ich diese Zeilen:

xxxxxx


yyyyyy


zzzzzz

und ich möchte, dass es so ist:

xxxxxx
yyyyyy
zzzzzz

Was sollte der Code dafür sein?


2
Ihr sed Befehl sieht gut aus, es sollte funktionieren
perreal

Der obige Befehl würde nicht funktionieren, selbst wenn Sie kein Leerzeichen / Tabulator, sondern CR + LF-Zeilenenden haben .
devnull

Antworten:


627

Möglicherweise befinden sich Leerzeichen oder Tabulatoren in Ihrer "leeren" Zeile. Verwenden Sie POSIX-Klassen mit sed, um alle Zeilen zu entfernen, die nur Leerzeichen enthalten:

sed '/^[[:space:]]*$/d'

Eine kürzere Version, die ERE verwendet, zum Beispiel mit gnu sed:

sed -r '/^\s*$/d'

(Beachten Sie, dass sed PCRE NICHT unterstützt.)


3
@HuStmpHrrr gnu sed unterstützt PCRE überhaupt nicht. es ist ERE mit-r
Kent

8
OS X benötigt sed -i "" '/^[[:space:]]*$/d' <filename>,
jww

@BernieReiter stimmt ^\s*$mit allen "leeren" Zeilen überein. Leer bedeutet hier, dass die Zeile keine Zeichen enthält oder dass die Zeile nur leere Zeichenfolgen enthält (z. B. Leerzeichen). Alle übereinstimmenden Zeilen werden mit dem dBefehl von sed entfernt .
Kent

96

Mir fehlt die awkLösung:

awk 'NF' file

Welches würde zurückkehren:

xxxxxx
yyyyyy
zzzzzz

Wie funktioniert das? Da NFfür "Anzahl der Felder" steht, haben diese leeren Zeilen 0 fiedls, so dass awk 0 zu False auswertet und keine Zeile gedruckt wird; Wenn jedoch mindestens ein Feld vorhanden ist, lautet die Auswertung True und führt awkdie Standardaktion aus: Drucken Sie die aktuelle Zeile.


1
Whoah. Läuft sogar mit BSDs "minimierter" Version von awk (Version 20121220 (FreeBSD). Danke :-)
Bernie Reiter

@BernieReiter du bist willkommen :) Ja, das ist eine sehr grundlegende Redewendung, die alle awk-Versionen erlauben.
Fedorqui 'SO hör auf zu schaden'

Und es ist so viel schneller, obwohl ich - für einen schnellen und schmutzigen Test - zweimal awk aufrufe: $ time (topic companies <data.tpx | awk 'NF' - | awk -f dialog_menu.awk -) real 0m0.006s user 0m0.000s sys 0m0.008s $ time (topic companies <data.tpx | gsed '/^\s*$/d' | awk -f dialog_menu.awk -) real 0m0.014s user 0m0.002s sys 0m0.006s Würdest du eine raffinierte Möglichkeit kennen, dies in ein awk-Skript wie z. B. ein Muster aufzunehmen? awk '/ mypattern / {do stuff ...}'
Bernie Reiter

@BernieReiter kann man sagen awk 'NF {do stuff...}'.
Fedorqui 'SO hör auf zu schaden'

1
Beachten Sie, dass dadurch auch Zeilen mit Leerzeichen ignoriert werden.
wisbucky

60

sed '/^$/d'sollte in Ordnung sein, erwarten Sie, die Datei an Ort und Stelle zu ändern? Wenn ja, sollten Sie die -iFlagge verwenden.

Vielleicht sind diese Zeilen nicht leer. Wenn dies der Fall ist, schauen Sie sich diese Frage an. Entfernen Sie leere Zeilen aus txtfiles, entfernen Sie Leerzeichen vom Anfang und Ende der Zeile. Ich glaube, das ist es, was Sie erreichen möchten .


Ja. Ich ändere eine Datei. * .csv. Wie soll das -i auf den Befehl sed gesetzt werden?
Jonas

2
sed -i '/^$/d'ist eine Möglichkeit, es zu tun.
Alberto Zaccagni

49

1
Diese werden in Ihrem Online-Tool korrekt angezeigt, []sollten jedoch nicht in einem Klammerausdruck maskiert werden, sodass der Code hier nicht korrekt ist für \[\[:space:\]\]oder \[ \t\]- sollte [[:space:]]und sein [ \t].
Benjamin W.

1
@ BenjaminW. Danke, dass du das verstanden hast. Diese stammten nicht vom ursprünglichen Autor, sondern stammten aus Edit 3, als es von normalem Text in "Code" geändert wurde, wodurch das "\" Escape "entlarvt" wurde. Ich habe sie jetzt repariert.
wisbucky

30

Ich glaube, das ist das einfachste und schnellste:

cat file.txt | grep .

Wenn Sie auch alle Leerzeichen ignorieren müssen, versuchen Sie Folgendes:

cat file.txt | grep '\S'

Beispiel:

s="\
\
a\
 b\
\
Below is TAB:\
    \
Below is space:\
 \
c\
\
"; echo "$s" | grep . | wc -l; echo "$s" | grep '\S' | wc -l

Ausgänge

7
5

5
Keine Notwendigkeit cat, grepnimmt auch Dateien:grep . file.txt
Ciro Santilli 法轮功 冠状 病 六四 六四 16

3
Ja, ich weiß, aber in der ersten Frage wurde nicht erwähnt, ob die Quelle eine Datei oder etwas anderes ist. Die Lösung lautet also "|" und davor nur ein Beispiel für eine Quelle. Einfach, um die Lösung von der Quelle der Linien zu unterscheiden.
Vadim

2
grep '\S'ist definitiv nicht tragbar. Wenn Sie haben grep -P, können Sie verwenden, grep -P '\S'aber es wird auch nicht auf allen Plattformen unterstützt.
Tripleee

Der Nachteil im grep .Vergleich zu den anderen Lösungen ist, dass der gesamte Text rot hervorgehoben wird. Die anderen Lösungen können die ursprünglichen Farben beibehalten. Vergleichen Sie unbuffer apt search foo | grep .mitunbuffer apt search foo | grep -v ^$
wisbucky

15

Mit Hilfe der akzeptierten Antwort hier und die akzeptierten Antwort oben, habe ich verwendet:

$ sed 's/^ *//; s/ *$//; /^$/d; /^\s*$/d' file.txt > output.txt

`s/^ *//`  => left trim
`s/ *$//`  => right trim
`/^$/d`    => remove empty line
`/^\s*$/d` => delete lines which may contain white space

Dies deckt alle Grundlagen ab und funktioniert perfekt für meine Bedürfnisse. Ein großes Lob an die Originalposter @Kent und @kev


5

Sie können sagen:

sed -n '/ / p' filename    #there is a space between '//'

.. was bedeutet print all lines except the empty one(s)und ruhig sein
Timo

2

Sie können so etwas auch mit "grep" machen:

egrep -v "^$" file.txt


2

Sie sehen höchstwahrscheinlich das unerwartete Verhalten, weil Ihre Textdatei unter Windows erstellt wurde, sodass die Zeilenende-Sequenz lautet \r\n. Sie können dos2unix verwenden, um es in eine Textdatei im UNIX-Stil zu konvertieren, bevor Sie sed ausführen oder verwenden

sed -r "/^\r?$/d"

um Leerzeilen zu entfernen, unabhängig davon, ob der Wagenrücklauf vorhanden ist oder nicht.


Hallo, was macht die -rFlagge und ist es möglich, sie zu kombinieren -i, um die Datei direkt zu ändern und das Drucken auf dem Bildschirm zu vermeiden. Darüber hinaus denke ich, dass dieser Befehl auch funktionieren würde alssed -r "/^\r$/d"
Alexander Cska

2

Eine weitere Option , ohne sed, awk, perl, usw.

strings $file > $output

Zeichenfolgen - Drucken Sie die Zeichenfolgen druckbarer Zeichen in Dateien.


Meinst du stringsstatt string?
Mickael B.

Hallo @MickaelB. Du hast recht, ich repariere es.
user319660

0

Meine bashspezifische Antwort lautet, die Verwendung des perlSubstitutionsoperators mit dem globalen Musterflag gwie folgt zu empfehlen :

$ perl -pe s'/^\n|^[\ ]*\n//g' $file
xxxxxx
yyyyyy
zzzzzz

Diese Antwort veranschaulicht die Berücksichtigung, ob die leeren Zeilen Leerzeichen enthalten ( [\ ]*), und die Verwendung |zum Trennen mehrerer Suchbegriffe / Felder. Getestet auf macOS High Sierra und CentOS 6/7.

Zu Ihrer Information, der ursprüngliche Code des OP sed '/^$/d' $filefunktioniert in bashTerminal unter macOS High Sierra und CentOS 6/7 Linux in einem Hochleistungs-Supercomputing-Cluster einwandfrei.


-3

Für mich mit FreeBSD 10.1 mit sed funktionierte nur diese Lösung:

sed -e '/^[     ]*$/d' "testfile"

Im Inneren []befinden sich Leerzeichen und Tabulatorsymbole.

Testdatei enthält:

fffffff next 1 tabline ffffffffffff

ffffffff next 1 Space line ffffffffffff

ffffffff empty 1 lines ffffffffffff

============ EOF =============
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.