Entfernen Sie Linien, die nicht mit einem Muster beginnen, aus einem bestimmten Satz von Mustern

10

Ich habe eine Datei, die Daten wie diese enthält:

report aaaaaaaa  
-  ..  
-th bbbbbbbbb  
-to ccccccccc

.. --.

Frage: Ich möchte alle Zeilen entfernen, die nicht mit folgenden Zeichenfolgen beginnen:

report  
-th  
-to

Das bedeutet, dass die Wunschausgabe alle mittleren unerwünschten Punkte und Hashes entfernt und folgendermaßen aussieht:

report aaaaaaaa  
-th bbbbbbbbb  
-to ccccccccc

sed// awk/ grepetc jede Lösung, die funktioniert.

Rana Khan
quelle

Antworten:

15

Verwenden Sie sed, um die vorhandene Datei zu ändern:

sed -i '/^\(report\|-t\(h\|o\)\)/!d' your_file

Dies weist sedan, alle Zeilen zu löschen, die nicht mit dem Muster übereinstimmen. Das Muster selbst ist ^(Zeilenanfang), gefolgt von entweder reportoder -tgefolgt von entweder hoder o.

Sie sollten beachten, dass dies keine tatsächliche direkte Änderung ist: sedErstellt eine temporäre Sicherungskopie und überschreibt damit die Originaldatei.

Wenn Sie sedeine Sicherungskopie der Originaldatei aufbewahren möchten (was eine gute Idee sein kann, wenn die Datei wichtige Daten enthält), geben Sie dem -iSwitch eine Erweiterung zum Erstellen einer Sicherungsdatei:

sed -i'.bak' -e '/^\(report\|-t\(h\|o\)\)/!d' your_file

ändert your_fileund erstellt ein Backup des aufgerufenen Originals your_file.bak.

Eine Randnotiz

Bitte missverstehen Sie meine Absichten nicht und beleidigen Sie dies nicht, aber ich habe festgestellt, dass Sie viele ähnliche Fragen zu Regex / Textverarbeitung haben. Ich rate Ihnen , das Lernen zu beginnen sed, awkund grepauf eigene Faust zu helfen beschleunigen Ihre Produktivität. Versteh mich nicht falsch, ich bin nur allzu glücklich zu helfen (wie die meisten Leute hier); Ich denke nur, dass Sie enorm davon profitieren werden, wenn Sie diese Werkzeuge für Ihren täglichen Gebrauch in die Hand nehmen.

Um zu beweisen, wie hilfreich die Leute hier sind, sollten Sie den Vorschlag von @ slm in den Kommentaren unten berücksichtigen und jederzeit bei Fragen in diesem Chatroom vorbeischauen .

Joseph R.
quelle
1
Ihr regulärer Ausdruck erscheint unnötig kryptisch. Ich denke, Sie verwenden tatsächlich mehr Zeichen, als wenn Sie die drei Optionen nur explizit aufgelistet hätten.
Nispio
1
@nispio Ich weiß, aber es ist wahrscheinlich effizienter, wenn die betreffende Datei groß ist.
Joseph R.
Interessant. Ich habe Regexps immer in Bezug auf Länge oder Lesbarkeit gemessen. Ich habe nie viel über die Ausführungsgeschwindigkeit nachgedacht. Ich glaube nicht, dass ich genug darüber weiß, wie sie bewertet werden, um zu beurteilen, was schnell ist, aber ich gehe davon aus, dass es auch implementierungsspezifisch ist, oder?
Nispio
3
Wenn Sie allgemeine Fragen haben, die nicht zum Q & A-Stil passen, können Sie jederzeit versuchen, uns im Chatroom für diese Website zu unterhalten. chat.stackexchange.com/rooms/26/unix-and-linux . Einige von uns leben dort 8-)
slm
@slm Danke dafür. Ich werde es meiner Antwort hinzufügen.
Joseph R.
10

Sie können hierfür einfaches grep verwenden:

$ grep -e '^report\|^-th\|^-to' filename
pradeepchhetri
quelle
1
Es ist keine große Ersparnis, aber Sie könnten das -th/ -toin kombinieren -t[ho].
Kevin
grep -eoderegrep
Olivier Dulac
2

Verwenden von sed:

sed -n -e '/^report\|^-th\|^-to/p' filename
Nispio
quelle
Es ist keine große Ersparnis, aber Sie könnten das -th/ -toin kombinieren -t[ho].
Kevin
1
@ Kevin Das stimmt. Siehe mein Gespräch mit Joseph R. in den Kommentaren zu seiner Antwort.
Nispio
2

Verwenden von awk:

awk '/^report|^-t[ho]/' file
Jasonwryan
quelle
Es ist keine große Ersparnis, aber Sie könnten das -th/ -toin kombinieren -t[ho].
Kevin
1

Der Fragesteller hat zwei Punkte angesprochen:

  • Sie möchten eine Zeile entfernen, die nicht mit "report" oder "-th" oder "-to" beginnt.
  • Die gewünschte Ausgabe sollte "alle mittleren unerwünschten Punkte und Hashes (sic)" entfernen.

Die Lösungen befassen sich zu diesem Zeitpunkt mit dem ersten Punkt und damit auch mit dem zweiten. Angenommen, die Datei ist größer und sieht folgendermaßen aus:

report aaaaaaaa  
-  ..  
-th bbbbbbbbb  
-to ccccccccc
anything else
.. --.
-tp ddd
-tq eee
     -  -----

Würde es nicht notwendig sein, den zweiten Punkt von OP anzusprechen?

sed -r -i.bak '/^[ |.|-]*$/d' input-file 

erledigt die Aufgabe, vermutlich unerwünschte Linien zu entfernen, die nur Leerzeichen, Punkte und Striche enthalten, und den Rest beizubehalten, was auch immer das ist.
Ich würde denken, dass das Risiko beider Ansätze darin besteht, dass die Art der Datei nicht richtig definiert ist.


quelle
0

Verwenden von Perl:

perl -ne 'print if /^report|^-t[ho]/' filename > newfile

oder, zu bearbeiten anstatt (wie sed, perlwird auch eine temporäre Sicherung machen , so dies nicht wahr ist an Ort und Stelle bearbeiten):

perl -i.bak -ne 'print if /^report|^-t[ho]/' filename

Dadurch wird eine Kopie der aufgerufenen Originaldatei erstellt filename.bakund Ihre Originaldatei mit der bearbeiteten Version überschrieben.

terdon
quelle