Wie lösche ich aus einer Textdatei alle Zeilen, die eine bestimmte Zeichenfolge enthalten?

1789

Wie würde ich sed verwenden, um alle Zeilen in einer Textdatei zu löschen, die eine bestimmte Zeichenfolge enthalten?

Ein Uhrwerk Orange
quelle

Antworten:

2759

So entfernen Sie die Zeile und drucken die Ausgabe als Standard aus:

sed '/pattern to match/d' ./infile

So ändern Sie die Datei direkt - funktioniert nicht mit BSD sed:

sed -i '/pattern to match/d' ./infile

Gleich, aber für BSD sed (Mac OS X und FreeBSD) - funktioniert nicht mit GNU sed:

sed -i '' '/pattern to match/d' ./infile

So ändern Sie die Datei direkt (und erstellen ein Backup) - funktioniert mit BSD und GNU sed:

sed -i.bak '/pattern to match/d' ./infile
SiegeX
quelle
13
Danke, aber es scheint es nicht aus der Datei zu löschen, sondern nur den Inhalt der Textdatei ohne diese Zeichenfolge auszudrucken.
Ein Uhrwerk Orange
115
@A Clockwork: Ja, Sie müssen die Ausgabe entweder in eine neue Datei mit so etwas wie umleiten sed '/pattern to match/d' ./infile > ./newfileoder wenn Sie eine direkte Bearbeitung durchführen möchten, können Sie das -iFlag wie in sed hinzufügen sed -i '/pattern to match/d' ./infile. Beachten Sie, dass die -iFlagge GNU sed erfordert und nicht portabel ist
SiegeX
16
Für einige Aromen von Sed; Für das "-i" -Flag von sed musste eine Erweiterung bereitgestellt werden. (zB sed -i.backup '/pattern to match/d' ./infile) Das hat mich mit direkten Änderungen konfrontiert.
Avelis
9
@SiegeX Besser noch, wenden Sie keine Befehle wie sedauf Dateien an, die nicht versioniert sind.
MatrixFrog
84
Noch ein Hinweis für Mac OS X-Benutzer: Aus irgendeinem Grund muss für das Flag -i ein Argument übergeben werden, auch wenn es sich nur um eine leere Zeichenfolge handelt sed -i '' '/pattern/d' ./infile.
Geerlingguy
631

Es gibt viele andere Möglichkeiten, Zeilen mit einer bestimmten Zeichenfolge zu löschen sed:

AWK

awk '!/pattern/' file > temp && mv temp file

Rubin (1,9+)

ruby -i.bak -ne 'print if not /test/' file

Perl

perl -ni.bak -e "print unless /pattern/" file

Shell (Bash 3.2 und höher)

while read -r line
do
  [[ ! $line =~ pattern ]] && echo "$line"
done <file > o
mv o file

GNU grep

grep -v "pattern" file > temp && mv temp file

Und natürlich sed(das Drucken der Umkehrung ist schneller als das tatsächliche Löschen):

sed -n '/pattern/!p' file
kurumi
quelle
4
Wie lösche ich eine bestimmte Zeile mit einem Muster und auch die Zeile unmittelbar darüber? Ich habe eine Geldstrafe mit Tausenden solcher Zeilen zwischen verschiedenen Daten.
oortcloud_domicile
1
Unter OS / X behält die Shell-Variante keine führenden Leerzeichen bei, aber die grep -v-Variante hat bei mir gut funktioniert.
Paul Beusterien
13
Das sedBeispiel hat ein anderes Verhalten, es greift nur! es sollte so etwas sein sed -n -i '/pattern/!p' file.
Caesarsol
8
Die grep-Version funktioniert nicht, wenn jede Zeile dem Muster entspricht. Besser: grep -v "pattern" file > temp; mv temp fileDies kann je nach Rückgabewert für einige der anderen Beispiele gelten.
Chris Maes
1
"Das Drucken der Umkehrung ist schneller als das tatsächliche Löschen" - Nicht auf meinem Computer (2012 MacBook Air, OS X 10.13.2). Datei erstellen : seq -f %f 10000000 >foo.txt. sed d: time sed -i '' '/6543210/d' foo.txtechte 0m9.294s. sed! p: time sed -i '' -n '/6543210/!p' foo.txtechte 0m13.671s. (Bei kleineren Dateien ist der Unterschied größer.)
jcsahnwaldt sagt GoFundMonica
252

Sie können sed verwenden, um Zeilen in einer Datei zu ersetzen. Es scheint jedoch viel langsamer zu sein, als grep für die Umkehrung in eine zweite Datei zu verwenden und dann die zweite Datei über das Original zu verschieben.

z.B

sed -i '/pattern/d' filename      

oder

grep -v "pattern" filename > filename2; mv filename2 filename

Der erste Befehl dauert auf meinem Computer sowieso dreimal länger.

Slashdottir
quelle
19
Stimmen Sie auch Ihre Antwort ab, nur weil Sie einen Leistungsvergleich versucht haben!
Anuragw
4
+1 für die Option zum Überschreiben der aktuellen Datei mit der grep-Zeile.
Rhyuk
2
Die zweite 'grep'-Lösung ist auch besser für große Dateien
simoes
3
Ich bin gespannt, was der Leistungsunterschied wäre, wenn es wäresed '/pattern/d' filename > filename2; mv filename2 filename
Pete
9
(mit Ubuntus / usr / share / dict / words) grep und mv: 0.010s | an Ort und Stelle: 0.197s | sed und mv: 0.031s
ReactiveRaven
77

Der einfache Weg, dies mit GNU zu tun sed:

sed --in-place '/some string here/d' yourfile
Kevin Nguyen
quelle
56
Ein praktischer Tipp für andere, die über diesen Q & A-Thread stolpern und mit Shell-Skripten noch nicht vertraut sind: Kurze Optionen sind für die einmalige Verwendung in der Befehlszeile in Ordnung, aber lange Optionen sollten in Skripten bevorzugt werden, da sie besser lesbar sind.
Dennis
3
+1 für das Flag --in-place. Ich muss das an berechtigungsgeschützten Dateien testen. (müssen einige Benutzer schrubben.)
Bee Kay
8
Beachten Sie, dass die Long-Option nur für GNU sed verfügbar ist. Mac- und BSD-Benutzer müssen gsed installieren, um dies zu tun.
Matt
Ein weiterer Tipp: Wenn Ihre Regex nicht übereinstimmt, versuchen Sie es mit der -rOption (oder -E, abhängig von Ihrer Version). Dies ermöglicht die Verwendung von Regex Metazeichen +, ?, {...}und (...).
rjh
Dies ist die richtige Antwort, wenn auf Ihrer Festplatte kein Speicherplatz mehr vorhanden ist und Sie den Text nicht in eine andere Datei kopieren können. Dieser Befehl macht was in Frage gestellt wurde?
Ferreirabraga
38

Sie können Folgendes in Betracht ziehen ex(dies ist ein standardmäßiger befehlsbasierter Unix-Editor):

ex +g/match/d -cwq file

wo:

  • +führt den angegebenen Ex-Befehl ( man ex) aus, -cder auch ausgeführt wird wq(Schreiben und Beenden)
  • g/match/d- Ex-Befehl zum Löschen von Zeilen mit gegebenem match, siehe: Potenz von g

Das obige Beispiel ist eine POSIX-kompatible Methode zum direkten Bearbeiten einer Datei gemäß diesem Beitrag unter Unix.SE- und POSIX-Spezifikationen fürex .


Der Unterschied zu sedist, dass:

sedist ein S tream ED itor, kein Dateieditor. BashFAQ

Es sei denn, Sie genießen nicht portierbaren Code, E / A-Overhead und einige andere schlimme Nebenwirkungen. Grundsätzlich sind einige Parameter (wie z. B. in-place / -i) nicht standardmäßige FreeBSD-Erweiterungen und möglicherweise unter anderen Betriebssystemen nicht verfügbar.

Kenorb
quelle
5
Das ist toll ... wenn ich man exes gibt mir den Mann vim, so scheint es , exist ein Teil von vim ... wenn ich für richtig , dass Mittel , um die Muster - Syntax zu verstehen matchist vimregex.com , die POSIX und PCRE Aromen ähnlich , aber anders ist?
Anentropic
1
:g ist ein POSIX-kompatibler Befehl mit einigen geringfügigen Unterschieden . Ich gehe davon aus, dass PCRE darauf basiert.
Kenorb
16

Ich hatte auf dem Mac damit zu kämpfen. Außerdem musste ich es mit variablem Ersatz machen.

Also habe ich verwendet:

sed -i '' "/$pattern/d" $file

Wo $fileist die Datei, in der das Löschen erforderlich ist, und wo $patternist das Muster, das zum Löschen abgeglichen werden soll?

Ich habe das ''aus diesem Kommentar ausgewählt .

Hier ist die Verwendung von doppelten Anführungszeichen in zu beachten "/$pattern/d". Variable funktioniert nicht, wenn wir einfache Anführungszeichen verwenden.

Aniket Sinha
quelle
3
Mac sedbenötigt einen Parameter nach -i. Wenn Sie also keine Sicherung wünschen, müssen Sie immer noch eine leere Zeichenfolge hinzufügen:-i ''
wisbucky
Für den Shell-Gebrauch sed -i "/$pattern/d" $file. Vielen Dank für Ihre Antwort.
Ashwaqar
14

Ich habe einen kleinen Benchmark mit einer Datei erstellt, die ungefähr 345 000 Zeilen enthält. Der Weg mit grepscheint sedin diesem Fall etwa 15-mal schneller zu sein als die Methode.

Ich habe sowohl mit als auch ohne die Einstellung LC_ALL = C versucht, es scheint die Timings nicht wesentlich zu ändern. Die Suchzeichenfolge (CDGA_00004.pdbqt.gz.tar) befindet sich irgendwo in der Mitte der Datei.

Hier sind die Befehle und die Timings:

time sed -i "/CDGA_00004.pdbqt.gz.tar/d" /tmp/input.txt

real    0m0.711s
user    0m0.179s
sys     0m0.530s

time perl -ni -e 'print unless /CDGA_00004.pdbqt.gz.tar/' /tmp/input.txt

real    0m0.105s
user    0m0.088s
sys     0m0.016s

time (grep -v CDGA_00004.pdbqt.gz.tar /tmp/input.txt > /tmp/input.tmp; mv /tmp/input.tmp /tmp/input.txt )

real    0m0.046s
user    0m0.014s
sys     0m0.019s
Jadzia
quelle
Auf welcher Plattform bist du? Welche Versionen von sed / perl / grep verwenden Sie?
Hagello
Die Plattform, die ich benutze, ist Linux (Gentoo). Die sed-Version ist GNU sed v 4.2.2, die Perl-Version Perl 5 (ich kann nicht sagen, welche Revision ich zum Zeitpunkt des Tests verwendet habe) und grep (GNU) ist Version 3.0.
Jadzia
14

Sie können dies auch verwenden:

 grep -v 'pattern' filename

Hier -vwird nur ein anderes Muster als Ihr Muster gedruckt (dies bedeutet, dass die Übereinstimmung umgekehrt wird).

Bhuvanesh
quelle
Wie kann ich Zeilen in einem Verzeichnis löschen, die eine bestimmte Zeichenfolge enthalten
namannimmo
13

Um ein inplace-ähnliches Ergebnis zu erzielen grep, können Sie Folgendes tun:

echo "$(grep -v "pattern" filename)" >filename
Jahid
quelle
4
Dies ist nur gut für die bashShell oder ähnliches (nicht tcsh).
Esmit
4
perl -i    -nle'/regexp/||print' file1 file2 file3
perl -i.bk -nle'/regexp/||print' file1 file2 file3

Der erste Befehl bearbeitet die Datei (en) an Ort und Stelle (-i).

Der zweite Befehl macht dasselbe, behält jedoch eine Kopie oder Sicherung der Originaldatei (en) bei, indem .bk zu den Dateinamen hinzugefügt wird (.bk kann in irgendetwas geändert werden).

Kjetil S.
quelle
2

echo -e "/thing_to_delete\ndd\033:x\n" | vim file_to_edit.txt

Shizzmo
quelle
2

Nur für den Fall, dass jemand dies für genaue Übereinstimmungen von Zeichenfolgen tun möchte, können Sie das -wFlag in grep - w für das Ganze verwenden. Das heißt, wenn Sie beispielsweise die Zeilen mit der Nummer 11 löschen möchten, aber die Zeilen mit der Nummer 111 beibehalten möchten:

-bash-4.1$ head file
1
11
111

-bash-4.1$ grep -v "11" file
1

-bash-4.1$ grep -w -v "11" file
1
111

Es funktioniert auch mit dem -fFlag, wenn Sie mehrere exakte Muster gleichzeitig ausschließen möchten. Wenn "Blacklist" eine Datei mit mehreren Mustern in jeder Zeile ist, die Sie aus "Datei" löschen möchten:

grep -w -v -f blacklist file
FatihSarigol
quelle
Ein bisschen irreführend. -w, --word-regexp Select only those lines containing matches that form whole words.vs.-x, --line-regexp Select only those matches that exactly match the whole line. For a regular expression pattern, this is like parenthesizing the pattern and then surrounding it with ^ and $.
Sai
1
cat filename | grep -v "pattern" > filename.1
mv filename.1 filename
Andrey Izman
quelle
Sie überschreiben eine Datei, während sie noch verwendet wird.
Davor Cubranic
@DavorCubranic behoben
Andrey Izman
0

um den behandelten Text in der Konsole anzuzeigen

cat filename | sed '/text to remove/d' 

um behandelten Text in einer Datei zu speichern

cat filename | sed '/text to remove/d' > newfile

behandelte Textinformationen an eine vorhandene Datei anhängen

cat filename | sed '/text to remove/d' >> newfile

Um bereits behandelten Text zu behandeln, entfernen Sie in diesem Fall mehr Zeilen von dem, was entfernt wurde

cat filename | sed '/text to remove/d' | sed '/remove this too/d' | more

Das | morewird Text in Blöcken von jeweils einer Seite anzeigen.

Nassim
quelle
0

Sie können gute alte verwenden edin ähnlicher Weise , um eine Datei zu bearbeiten die Antwort , dass Anwendungen ex. Der große Unterschied in diesem Fall besteht darin, dass eddie Befehle über die Standardeingabe und nicht als Befehlszeilenargumente wie excan verwendet werden. Wenn Sie es in einem Skript verwenden, können Sie dies normalerweise verwenden, indem Sie printfBefehle an das Skript weiterleiten :

printf "%s\n" "g/pattern/d" w | ed -s filename

oder mit einem Heredoc:

ed -s filename <<EOF
g/pattern/d
w
EOF
Shawn
quelle