Warum funktioniert der $ -Anker am Zeilenende nicht mit dem Befehl grep, obwohl sich der ^ -Anker am Zeilenende befindet?

19

Sehr neu in UNIX, aber nicht neu in der Programmierung. Terminal auf dem MacBook verwenden. Zum Verwalten und Durchsuchen von Wortlisten für die Kreuzworträtselkonstruktion versuche ich, mit dem Befehl Grep und seinen Variationen vertraut zu werden. Scheint ziemlich unkompliziert zu sein, aber ich muss mich schon früh mit dem befassen, was ich für einen einfachen Fall hielt.

Wenn ich eintrete

grep "^COW" masternospaces.txt

Ich bekomme, was ich will: eine Liste aller Wörter, die mit COW beginnen.

Aber wenn ich eintrete

grep "COW$" masternospaces.txt

Ich erwarte eine Liste von Wörtern, die mit COW enden (es gibt viele solcher Wörter), und es wird überhaupt nichts zurückgegeben.

Die Datei ist eine reine Textdatei, in der jede Zeile nur ein Wort (oder eine Wortgruppe ohne Leerzeichen) in Großbuchstaben enthält.

Irgendeine Idee, was hier passieren könnte?

DTalvacchio
quelle
3
Woher stammt die Datei masternospaces.txt? ist es möglich, dass es Windows-artige Leitungsabschlüsse (CR-LF) anstelle von Unix-artigen LFs hat?
Steeldriver
2
Nicht sicher, aber suchen Sie nach einem Listenwort oder einer Liste von Zeilen ... ?
mikeserv
steeldriver-- So etwas war mein erster Gedanke. Ich war mir nicht sicher, wie ich überprüfen sollte, was dort vor sich ging oder welche Möglichkeiten es gab. Angenommen, eine Endretoure sei eine Endretoure. Diese Datei ist ein umfangreiches Kompendium aus wenigen Quellen. Ich bin mir nicht mal sicher, welches die Originaldatei ist. Mindestens drei Textverarbeitungsprogramme wurden sowohl auf PC- als auch auf Mac-Computern ausgeführt. Was könnte der beste Weg sein, um zu sehen, welche Art von Terminierungen verwendet wird?
DTalvacchio
mikeserv-- In dieser TXT-Datei ist jede Zeile nur ein Wort (oder eine Phrase ohne Leerzeichen zwischen den Wörtern, also wieder ein "Wort"). Also suche ich nach Zeilen, nehme ich an. . . Nur, dass jede Zeile nur eines der Wörter enthält, die ich für Kreuzworträtselzwecke in Betracht ziehe.
DTalvacchio
1
Mit können hexdumpSie genau überprüfen, wie Ihre Zeilenenden formatiert sind. Ich schlage vor , Sie meinen Lieblings Format verwenden: hexdump -e '"%08_ad (0x%08_ax) "8/1 "%02x "" "8/1 "%02x "' -e '" "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt. Überprüfen Sie bei der Ausgabe die Zeilenenden: 0a-> LF, 0d-> CR.
User43791

Antworten:

23

Wie @steeldriver bereits erwähnte, wird das Problem wahrscheinlich durch einen anderen Zeilenendestil als what verursacht grep erwartet.

Um die Zeilenenden zu überprüfen

Mit können hexdumpSie genau überprüfen, wie Ihre Zeilenenden formatiert sind. Ich schlage vor, Sie verwenden mein Lieblingsformat:

hexdump -e '"%08_ad (0x%08_ax)    "8/1 "%02x ""   "8/1 "%02x "' -e '"    "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt

Überprüfen Sie bei der Ausgabe die Zeilenenden: 0a-> LF, 0d-> CR. Ein sehr kurzes Beispiel würde ungefähr so ​​aussehen:

$ hexdump -e '"%08_ad (0x%08_ax)    "8/1 "%02x ""   "8/1 "%02x "' -e '"    "8/1 "%_p""|"8/1 "%_p""\n"' masternospaces.txt
00000000 (0x00000000)    4e 6f 20 43 4f 57 20 65   6e 64 69 6e 67 0d 0a 45    No COW e|nding..E
00000016 (0x00000010)    6e 64 69 6e 67 20 69 6e   20 43 4f 57 0d 0a          nding in| COW..

Beachten Sie die Zeilenenden im DOS-Format: 0d 0a .

Zeilenenden ändern

Sie können hier oder hier nach verschiedenen Methoden zum Ändern von Zeilenenden mit verschiedenen Werkzeugen suchen, aber für eine einmalige Sache können Sie immer vi / vim verwenden:

vim masternospaces.txt
:set fileformat=unix
:wq

Grep, ohne etwas zu ändern

Wenn Sie grepunabhängig vom Zeilenende nur eine Übereinstimmung finden möchten , können Sie die Zeilenenden immer wie folgt festlegen:

grep 'COW[[:cntrl:]]*$' masternospaces.txt

Wenn eine leere Zeile angezeigt wird, können Sie anhand der folgenden -vOptionen überprüfen, ob Sie tatsächlich eine Übereinstimmung gefunden haben cat:

grep 'COW[[:cntrl:]]*$' masternospaces.txt | cat -v

Mein persönlicher Favorit

Sie können die Ausgabe auch mit den sedfolgenden Methoden standardisieren :

sed -n '/COW^M*$/{;s/^M//g;p;};' masternospaces.txt

Woher ^Mkommt man, wenn man Ctrl-V Ctrl-Mauf der Tastatur tippt ?

Hoffe das hilft!

user43791
quelle
Das ist alles sehr hilfreich. Ich habe heute keine Zeit mehr, werde aber morgen alles genau durchsehen und sehen, was was ist. Wenn in der Zwischenzeit jemand von Ihnen einen Link zu Ihrem bevorzugten Unix-Befehlsreferenzhandbuch hat, damit ich mir selbst ein wenig über die Funktionsweise der Dinge beibringen kann, würde ich es begrüßen. Ich habe hier und da Stücke gesammelt, aber noch keine Quelle gefunden, an die ich mich für Erklärungen wenden kann. Vielen Dank an alle und wir werden morgen mit einem hoffentlich erfolgreichen Update einchecken. --D
DTalvacchio
Es ist schade, dass dieser Beitrag keinen Abschluss hat, zumindest für mich. Ich kann für mein ganzes Leben nicht herausfinden, wie ich das Ende der Linie erreichen soll. Wenn ich einen Hex-Dump mache, kann ich keine nette Zeile finden, die wie Ihr Beispiel oben endet. Ich bin nicht mit Hex vertraut und lese es daher möglicherweise nicht richtig. Ich habe auch den [[:cntrl:]]@ user43791 Vorschlag ausprobiert und er passt immer noch nicht zu mir. Das macht keinen Sinn. Ich benutze GNU grep 2.20 und analysiere die Ausgabe von nDPI, die in eine Textdatei geschrieben wurde
harperville
@harperville Wenn Sie cat -v yourfile.ext, was sehen Sie?
user43791
Nun, nichts zu aufregend oder unerwartet. Nur die Inhalte, wie ich sie erwarten würde. Was genau suchen Sie? Ich kann die Ausgabe hier nicht einfügen, aber ich sehe nur den Inhalt. Regelmäßiger alter "ASCII English Text" nach file.
Harperville
@harperville Kein zusätzliches "^ M" am Ende jeder Zeile? Könnten Sie die ersten paar Zeilen Hex einfügen?
user43791
1

Obwohl Sie mit grep die 'Standard'-RegEx-Syntax verwenden können (wie in der Antwort von @ user43791) ), verfügt grep auch über andere Bezeichner, um die Eingabegrenzen zu kennzeichnen.

Die Matcher für den Anfang und das Ende der gesamten Zeile lauten \`(Backtick) (anstelle von ^) und \'(Apostroph) (anstelle von)$ ).

Für Ihren ursprünglichen Befehl würden Sie also Folgendes verwenden: grep "COW\'" masternospaces.txt

Randnotiz: Es ist auch wichtig zu beachten, dass ?und +wird wörtlich behandelt, es sei denn, Sie entkommen ihnen mit \?und\+ machen sie zu ihren RegEx-ähnlichen Selektor-Gegenstücken.

Quelle: grepSyntax für reguläre Ausdrücke

samthecodingman
quelle
grep nimmt ^ (caret) als Start und \ '(apostrophe) als Ende
GypsyCosmonaut
1

Ein anderer Weg, das \rvor dem grep zu entfernen :

... | dos2unix | egrep 'COW$' | ...

Ich mag es, dass es sehr klar ist, da ich mich nicht lange an solche Dinge erinnere [[:cntrl:]].

Javier
quelle
-2

"COW $" Wenn die Bash den Parameter für grep gesetzt hat, wurde dies als "COW" interpretiert, wobei "$" als "" behandelt wird, da $ ein Escape-Simbol ist. Wenn $ nichts mit einbezieht, wird es von der Bash-Shell als leere Zeichenfolge interpretiert. Verwenden Sie stattdessen grep 'COW $' masternospaces.txt.

Yangyang
quelle
3
da es keine gültige Erweiterung von gibt $, würde es von bash in Ruhe gelassen und von grep verwendet. Überzeugen Sie sich selbst: echo "COW$"- Der $wird noch da sein.
Jeff Schaller
-3

In BSD grep müssen Sie "$" entkoppeln und Ihre Zeichenfolge in doppelte Anführungszeichen setzen:

"COW\$"
user297403
quelle
1
Ähm ... nein. Das $wird für die Shell nicht besonders sein, da das Zeug danach kein gültiger Shell-Variablenname ist. Die Verwendung von einfachen Anführungszeichen um statische Zeichenfolgen ist eine bessere Idee, macht hier jedoch keinen Unterschied.
Kusalananda