Wie finde ich Linien, die zu einem Muster passen, und lösche sie?

14

In einer Datei mit vielen Zeilen möchte ich Zeilen löschen, die mit beginnen HERE IT IS.

Wie kann ich das nur mit Befehlszeilentools tun?

micgeronimo
quelle
2
Obwohl ein wenig unkonventionell, könnten Sie vimwie vim '+g/^HERE IT IS/d' +wq test.txt
folgt verwenden
@Doorknob, vielen Dank für den Hinweis. Eigentlich bin ich auf dem Weg, vim
micgeronimo 20.02.15

Antworten:

28

Versuchen sed :

sed -i '/^HERE IT IS/d' <file>

WARNUNG: Es ist besser, eine Sicherungskopie zu erstellen, wenn Sie -iswitch of verwendensed :

sed -i.bak '/^HERE IT IS/d' <file>

Die Originaldatei bleibt unverändert, <file>.bakund die geänderte Datei bleibt unverändert <file>.

heemayl
quelle
Wie kann ich ein Newline-Zeichen nach einer übereinstimmenden Zeichenfolge einfügen und in eine Newline schreiben?
Micgeronimo
2
sed -i 's/^HERE IT IS/HERE IT IS\n/' <file>
Heemayl
1
@micgeronimo: gerne helfen. Bitte überprüfen Sie meine Änderungen.
Heemayl
6
@micgeronimo versuchen, die Frage zu stellen, die Sie wirklich in Ihrer ursprünglichen Frage beantwortet haben möchten (denken Sie daran, dass Sie sie bearbeiten können), anstatt durch Kommentare, die möglicherweise bereinigt / gelöscht werden. Sie können verwenden sed '/^HERE IT IS/G' file.
Steeldriver
1
Sed Nutzung ist so pro.
LakshyaAg
17

Neben der sehr guten grepund sedAntworten , die Sie erhalten haben, sind hier einige andere Tools , die das gleiche tun können:

  • Einige Perl-Möglichkeiten:

    perl -ne '/^HERE IT IS/ || print' file > newfile
    perl -ne 'print if !/^HERE IT IS/' file > newfile
    perl -ne 'print unless /^HERE IT IS/' file > newfile
    

    Sie können den -iSchalter zu jedem Beispiel hinzufügen , um die Datei direkt zu bearbeiten:

    perl -i.bak -ne '/^HERE IT IS/ || print' file        
    
  • (gaffen

    awk '!/^HERE IT IS/' file > newfile
    

    Neuere Versionen (4.1.1 und höher) von GNU awk(der Standard awkunter Linux) können die Datei auch direkt bearbeiten:

    gawk -i inplace  '!/^HERE IT IS/' file
    
  • Shell ( bash, zsh, ksh, wahrscheinlich noch andere). Dies ist eine Art albern aber es können aber auch andere Werkzeuge sind besser gemacht werden.

    while IFS= read -r line; do 
      [[ $line =~ ^"HERE IT IS" ]] || printf "%s\n" "$line"
    done < file > newfile
    
terdon
quelle
1
Du zeigst nur! ;-) (aber du hast eine Gegenstimme bekommen, weil es klug ist und ich viel gelernt habe und der basheine hat mich zum LOL gemacht)
Fabby
In der Bash sollte Folgendes verwendet werden printf "%s\n" "$line": Zitieren von $ line, um Leerzeichen zu erhalten, und Vermeiden von Echoproblemen (Interpretieren von Sonderzeichen usw.). und vermeidet die Notwendigkeit, auch hinzuzufügen --.
Olivier Dulac
@OlivierDulac fair genug. Ich wollte die Dinge nicht für Randfälle komplizieren, aber da Cuanglm hinzugefügt hat IFS=und -r, kann ich genauso gut den ganzen Weg gehen und es robust machen.
Terdon
@terdon: es ist alles zum Besseren gut ^^ (und ich habe bereits +1 gegeben, da es für Anfänger sehr informativ ist)
Olivier Dulac
2
@OlivierDulac Ich kann Ihnen versichern, dass ich printf, IFS =, -r und quoting verwendet hätte, wenn ich auf Unix & Linux gepostet hätte :). Ich vereinfache oft Dinge für das AU-Publikum, die mit der Kommandozeile oft weniger vertraut sind.
Terdon
13

ich würde ... benutzen grep , um sie herauszufiltern. Zum Beispiel :

grep -v "^HERE IT IS" infile > outfile

Verschieben Sie dann die Ausgangsdatei zurück in die Infile-Datei.

Ben Hills
quelle
Clever denken
Anwar
5

sed ist definitiv der richtige Weg.

Durch diese geringfügige Änderung des Befehls @heemayl wird die Zeile gelöscht, unabhängig davon, ob im Muster die gleiche Groß- / Kleinschreibung verwendet wird oder nicht.

sed -i '/HERE IT IS/Id' <file>

Wenn Sie mehrere Dateien in einem Verzeichnis haben, in dem Sie dies tun möchten, können Sie es mit find like so kombinieren.

find . -maxdepth 1 -type f -exec sed -i.bak '/HERE IT IS/Id' {} +

Die Option maxdepth bedeutet, dass dies nicht in Verzeichnisse wiederkehrt.

Arronisch
quelle
4

Eine weitere Python-Option:

#!/usr/bin/env python3
[print(l, end = "") for l in open(f).readlines() if not l.startswith("HERE IT IS")]

Wobei f der Pfad zur Datei zwischen Anführungszeichen ist.

Jacob Vlijm
quelle
4

Grep

grep -P '^(?!HERE IT IS)' file

(?!HERE IT IS)Negative Lookahead-Behauptung, die bewirkt, dass die Regex-Engine nur dann mit der gesamten Zeilenstartgrenze übereinstimmt^ ( die normalerweise von übereinstimmt ), wenn die Zeichenfolge nicht folgtHERE IT IS

Python

#!/usr/bin/python3
import sys
fil = sys.argv[1]
with open(fil) as f:
    for line in f:
        if not line.startswith('HERE IT IS'):
            print(line, end="")

Speichern Sie das Skript beispielsweise in einer Datei script.pyund führen Sie es dann über den folgenden Befehl auf dem Terminal aus.

python3 script.py infile
Avinash Raj
quelle
Sie könnten dort Regex verwenden [print(l, end = "") for l in open(fil).readlines() if not re.match("HERE IT IS", l)], aber es ist nicht viel effizienter als startswith. Ich habe mich gefragt, wie [print(l, end = "") for l in open(f).readlines() if not l.startswith("HERE IT IS")]ich die Ausgabe in einer Liste nicht erzeugen kann.
Avinash Raj
Das erste Mal, als ich darauf stieß, sah es für mich seltsam aus. Es generiert einen Druckbefehl (oder eine Aktion, die Sie damit ausführen möchten) für alle Elemente in der definierten Liste.
Jacob Vlijm
Undeleting es, nur zum Spaß :)
Jacob Vlijm
1

Sie können Vim im Ex-Modus verwenden:

ex -sc 'g/^HERE IT IS/d' -cx file
  1. g globale Suche

  2. d löschen

  3. x speichern und schließen

Steven Penny
quelle