Ich habe eine Datei, deren Inhalt dem folgenden ähnlich ist.
0
0
0.2
0
0
0
0
Ich muss alle Zeilen mit einer einzigen Null entfernen.
Ich habe überlegt zu verwenden grep -v "0"
, aber dies entfernt auch die Zeile mit 0,2. Ich habe gesehen, dass ich die -w
Option verwenden könnte, aber das scheint auch nicht zu funktionieren.
Wie kann ich alle Zeilen entfernen, die nur eine einzige 0 enthalten, und alle diese Zeilen mit einer 0 beginnen lassen?
-w
, was hier fehlschlägt.grep
für diese Aufgabe zu verwenden? Und was genau meinst du mit einer einzigen Null ? Das klingt sehr nach einem XY-Problem .Antworten:
Von
man grep
:-w
schlägt fehl, weil das erste0
in0.02
als "Wort" betrachtet wird und daher diese Zeile übereinstimmt. Dies liegt daran, dass auf ein "Nicht-Wort" -Zeichen folgt. Sie können dies sehen, wenn Sie den ursprünglichen Befehl ohne ausführen-v
, dhgrep -w "0"
.quelle
-F
Option auch verwenden, da wir keine Regex-Muster verwenden, sondern nur einen einfachen String-Matching-F
(für mich überraschend) scheint ähnlich lange oder sogar etwas langsamer zu dauern (~ 5–10%). Daher bin ich mir nicht sicher, was der Vorteil wäre.grep
Vermutlich gibt es einen Sonderfall für Regexes ohne Metazeichen, da dies ein häufiger Anwendungsfall ist. Es ist überraschend, dassfgrep
dies langsamer wäre, aber es ist nicht überraschend, dass der Aufwand für das Erkennen dieses Sonderfalls beim Kompilieren eines kurzen Musters im Vergleich zur Zeit zum Scannen einer großen Datei vernachlässigbar ist. (Wenn es überhaupt einen Sonderfall erfordert, um so schnell zu gehen, gegen ein Muster mit einer Charakterklasse oderx.*y
.)grep
ein anderes Zeichen als\n
Zeilenumbruch als Zeilentrennzeichen erkannt wird . Wenn nicht, kann das implizite^
und$
dennoch zu einer Suche mit festen Zeichenfolgen werdenstrstr(big_buf, "\n0\n")
. (Oder0\n
zu Beginn eines Puffers.) Wir suchen jedoch nicht nur nach der ersten Übereinstimmung, die möglicherweise weit in einem großen Puffer liegt, sondern möchten auch effizient filtern. Aber theoretisch ist es nur ein 2-Byte-Memcmp am Anfang jeder Zeile, und Sie würden hoffen, dass sowohl fgrep als auch grep das sehen würden.Mit grep:
^
bedeutet Zeilenanfang,$
bedeutet Zeilenende.quelle
[a-Z0-9]
Während
grep
kann dafür verwendet werden (wie andere Antworten zeigen deutlich), lassen Sie uns einen Schritt zurück und überlegen , was Sie eigentlich wollen:Regex interpretiert Zeichensequenzdaten. Sie kennen keine Zahlen, nur einzelne Ziffern (und reguläre Kombinationen davon). Obwohl es in Ihrem speziellen Fall einen einfachen Hack um diese Einschränkung gibt, handelt es sich letztendlich um eine Nichtübereinstimmung der Anforderungen.
Sofern es keinen sehr guten Grund gibt,
grep
hier zu verwenden (z. B. weil Sie es gemessen haben und es wesentlich effizienter ist und Effizienz in Ihrem Fall von entscheidender Bedeutung ist), empfehle ich die Verwendung eines anderen Tools.awk
kann beispielsweise basierend auf numerischen Vergleichen filtern, z.Aber auch, um alle Zeilen zu erhalten, die Zahlen größer als Null enthalten:
Ich liebe Regex, es ist ein großartiges Werkzeug. Aber es ist nicht das einzige Werkzeug. Wie das Sprichwort sagt, wenn alles
grep
, was Sie haben, ist , sieht alles wie eine normale Sprache aus.quelle
printf '0\n1\n-1\na\nb\n0\n0 also\n0.0\n-0.0\n0*0\n' | awk '($1 == 0)'
passt auf :0
,0.0
und-0.0
... und auch0 also
! Nicht nur "0". (was manchmal benötigt wird, manchmal nicht). Wenn der Benutzer nur "0" möchte:awk '/^0$/'
(odergrep '^0$'
). Außerdem sollten Sie Folgendes bearbeiten: Der Benutzer muss hinzufügen!
, um den Test zu negieren, damit er0
(und andere Nullen) ausblendet und den Rest anzeigt. dh:awk '!( $0 == 0)'
$1 == "0"
>
und nicht!=
(oder gleichwertig! (… == …)
) verwendet, um hervorzuheben, dass dies ein willkürlicher numerischer Vergleich ist, nicht nur Gleichheit. Was Ihren anderen Kommentar betrifft, so ist dies völlig richtig, aber dann befinden wir uns im Wesentlichen wieder im Bereich des Zeichenfolgenvergleichs und der vorhandenen Lösung, diegrep
Werke verwendet (obwohl diesawk
natürlich auch funktioniert).$0=="0"
grep
's-w
ist etwas verworren, so dass die ursprüngliche Zeichenfolge in Wort- und Nichtwortbestandteile (alles außer Buchstaben, Ziffern oder Unterstrichen) aufgeteilt wird. Da es bereits aa gültiges Wort Bestandteil gestoßen0
in0.02
hatte es die Negation Logik behauptet die Zeile zu entfernen.Die Verwendung
sed
ist in diesem Zusammenhang etwas einfach, um nur die gesamten übereinstimmenden Wörter zu entfernenquelle
Wenn die zu löschenden Zeilen nur eine
0
gefolgt von der nächsten Zeile enthalten , können Sie diese Zeilen mit dem folgenden Befehl auswählen:Dadurch werden nur die Vorkommen gedruckt, die
0
sich gleichzeitig am Ende einer Zeile und am Anfang einer Zeile befinden . Die-v
Option kehrt dann unsere Auswahl um.quelle
-v
, also funktioniert sie nicht.-v
Option falsch verstanden , danke!grep -v "\b0\b"
grep -v "^0$"
-w funktioniert, aber in Ihrem Fall sind 0,2 zwei Wörter, da das Punktzeichen ein Worttrennzeichen ist.
quelle
grep -v "\b0\b"
funktioniert hier nicht wirklich. Welche Version von grep verwenden Sie?grep (BSD grep) 2.5.1-FreeBSD
unter MacOS undgrep (GNU grep) 2.16
Ubuntu\<
und\>
als Wortgrenzen, aber das wird den gleichen Effekt haben wie-w
Eine weitere Antwort aus Gründen der Abwechslung, vorausgesetzt, Sie haben eine PCRE-fähige Funktion
grep
Dies führt einen negativen Lookahead durch , der mit den Linien übereinstimmt, die mit einem Punkt beginnen
0
und auf den kein Punkt folgt. Dann werden-v
nicht übereinstimmende Zeilen verworfen. Sie können hier in Aktion sehenquelle
0123
, was nicht das ist, was das OP willAngenommen, jede Zeile, die nicht nur eine einzelne 0 ist, hat einen Punkt
grep '\.' file
quelle