Ich möchte eine Zeile aus einer Datei entfernen, die ein bestimmtes Zeichen nur einmal enthält. Wenn es mehr als einmal vorhanden ist oder nicht, dann behalte die Zeile in der Datei.
Beispielsweise:
DTHGTY
FGTHDC
HYTRHD
HTCCYD
JUTDYC
Hier ist das Zeichen, das ich entfernen möchte, C
so, dass der Befehl Zeilen entfernen sollte FGTHDC
und JUTDYC
weil sie C
genau einmal haben.
Wie kann ich das entweder sed
oder machen awk
?
quelle
awk
Feldtrenners!awk 'BEGIN { print "FS={" FS"}","OFS={" OFS "}";} {printf "%d fields : ",NF; for (i=1;i<=NF;i++) {printf "{" $i "} ";}; print "" }'
Um es zu sehen, kann man es tun und einige Zeilen füttern, einige mit mehreren Spces, und andere beginnen mit Leerzeichen)sed Ansatz:
-i
Option ermöglicht die direkte Änderung von Dateien/^[^C]*C[^C]*$/
- stimmt mit Zeilen überein, dieC
nur einmal enthaltend
- Übereinstimmende Zeilen löschenquelle
Dies kann erfolgen
sed
als:Code:
Ergebnisse:
Wie?
C
via zu und drucken Sie sie aus/C.*C/p
C
Via/C/d
, einschließlich der Zeilen, die bereits in Schritt 1 gedruckt wurdenquelle
Dies entfernt die Linien mit genau einem Vorkommen von C.
Der reguläre Ausdruck
[^C]
entspricht einem Zeichen, das nicht C (oder Zeilenumbruch) ist, und der Wiederholungsoperator (auch bekannt als Kleene-Stern)*
gibt null oder mehr Wiederholungen des vorhergehenden Ausdrucks an.Die Standardausgabe von
grep
(und den meisten anderen textorientierten Tools) ist die Standardausgabe. Leiten Sie zu einer neuen Datei um und verschieben Sie sie möglicherweise über die Originaldatei, wenn Sie dies wünschen. Dieselbe Regex kann für die direktesed -i
Bearbeitung verwendet werden:(Auf einigen Plattformen, insbesondere * BSD einschließlich macOS,
-i
erfordert die Option ein Argument wie-i ''
.)quelle
sed -i '/^[^C]*C[^C]*$/d' file
- klingt wie es vorher gepostet wurde, wie denkst du, Plagiat?grep
Antwort angefangen, aber sie erstreckt sich offensichtlich leicht auf diesed -i
Variante. Ich habe Ihre Antwort nicht gesehen, weil ich nach vorherigengrep
Antworten gesucht habe .-i
mitsed
und stattdessen in eine neue Datei umleiten und das Original mit , dass ersetzen , wenn dassed
Dienstprogramm ohne Fehler beendet.grep -vx '[^C]*C[^C]*'
grep
weil es klarer und robuster ist (insbesonderesed
hat es einen weniger informativen Exit-Code).Das POSIX-Tool für Skriptbearbeitungen einer Datei (anstatt den geänderten Inhalt als Standardausgabe auszudrucken) ist
ex
.Natürlich können Sie verwenden,
sed -i
wenn Ihre Version von Sed dies unterstützt. Beachten Sie jedoch, dass dies nicht portierbar ist, wenn Sie ein Skript schreiben, das auf verschiedenen Systemtypen ausgeführt werden soll.David Foerster fragte in den Kommentaren:
Antwort: Ja.
Für
printf
vs. istecho
es eine Frage der Portabilität; siehe Warum ist printf besser als echo? Außerdem ist es einfacher, Zeilenumbrüche zwischen Befehlen mit zu verteilenprintf
.Für
printf ... | ex
vs.ex -c ...
ist es eine Frage der Fehlerbehandlung. Für diesen speziellen Befehl wäre es nicht wichtig, aber im Allgemeinen ist es so; Versuchen Sie zum Beispiel Puttenin einem Skript. Vergleichen Sie Folgendes:
Der erste hängt und wartet auf die Eingabe. Die zweite wird beendet, wenn EOF vom
ex
Befehl empfangen wird , sodass das Skript fortgesetzt wird. Es gibt alternative Problemumgehungen, z. B.s///e
, die jedoch nicht von POSIX angegeben werden. Ich bevorzuge die Verwendung des oben gezeigten tragbaren Formulars.Für den
g
Befehl muss am Ende eine neue Zeile stehen, und ich bevorzuge esprintf
, die Befehle zu umbrechen, anstatt eine neue Zeile in einfache Anführungszeichen einzubetten.quelle
printf
und nichtecho
oder so etwasex -c COMMAND
?printf
vs.echo
(obwohl ich es normalerweise nur vorziehe,echo
wenn das Argument fest codiert ist), aber ich habe es bisher nichtex
ausgiebig verwendet .Hier sind einige Optionen für die Verwendung von Perl.
Da Sie nur mit einem einzelnen Zeichen übereinstimmen, können Sie
tr/C//
(eine Übersetzung ohne Ersatz) verwenden, um die Anzahl der Übereinstimmungen vonC
:Wenn Sie einer mehrstelligen Zeichenfolge oder einem regulären Ausdruck entsprechen möchten, können Sie im Allgemeinen Folgendes verwenden:
Dadurch werden die Übereinstimmungen des regulären Ausdrucks
/C/g
einer Liste@m
zugewiesen und Zeilen gedruckt, wenn die Länge dieser Liste nicht beträgt1
.Der
-i
Schalter kann hinzugefügt werden, um "an Ort und Stelle" zu bearbeiten.quelle
quelle
sed
, dass GNUt #...
normalerweise zu dem#...
in den meisten anderensed
Implementierungen aufgerufenen Label verzweigt .!b
ist GNU sed, da Branch nichts außer einem Label oder einer Newline danach mag.b
,t
,:
,}
(undr file
,w file
...) kann nicht einen Befehl nach dem sie auf der gleichen Linie haben. Sie können auch separate-e
Optionen verwenden.g
Modifikator hinzuzufügen .Für alle, die
awk
speziell wollen , würde ich anbietenÜberspringen Sie die Zeile, wenn sie mit dem Muster übereinstimmt, und drucken Sie sie anderweitig aus. Sie brauchen nicht wirklich
{print}
, Sie können einen//
Standarddruck verwenden, aber ich denke, es ist klarer formuliert.Mein erster Gedanke war,
egrep -v
mit dem gleichen Muster zu arbeiten, aber das beantwortet die gestellte Frage nicht wirklich.quelle
{next}
? Sagen Sie einfachawk '/pattern/ {next} 1'
und alle Zeilen, die nicht zum Muster passen, werden gedruckt. Oder besser,awk '!/pattern/'
um diese direkt auszudrucken.!/pattern/
(was mir irgendwie durch den Kopf ging), aber ich würde viel lieber eine selbsterklärende//{print}
als eine kryptische sehen1
. Nehmen Sie an, dass die nächste Person die geringste Kompetenz und Geläufigkeit für die Pflege Ihres Codes besitzt, um ihn nicht ernsthaft weniger effizient oder effektiv zu machen.