2016-08-02 35 views
1

ich data.txt haben werden, die das folgende Formatbash grep für eine Mischung aus Sonderzeichen, von denen einige interpretiert buchstäblich

blah<TAB>string1_with_spaces_quotes_dots_etc<TAB>blah 
blah<TAB>string2_with_spaces_quotes_dots_etc<TAB>blah 
... 

Einige der stringJ_... erscheinen mehr als einmal hat. Die Datei ist in keiner Weise sortiert.

Ich habe auch strings.txt, die die Form haben

stringA_with_spaces_quotes_dots_etc 
stringC_with_spaces_quotes_dots_etc 
stringB_with_spaces_quotes_dots_etc 
... 

Diese Strings nur einmal erscheinen, aber diese Datei ist entweder nicht sortiert.

Was ich brauche, ist für jede Zeichenfolge von strings.txt finden Linien in data.txt, wo die mittlere Saite ist genau derjenige von strings.txt. So zum Beispiel, wenn die Zeichenfolge ich suche ist

foo. 

Dann brauche ich

blah<TAB>foo.<TAB>blah 

die folgenden Zeilen zu extrahieren, aber nicht Zeilen wie

blah<TAB>foo. bar<TAB>blah 
blah<TAB>foo<TAB>blah 

Die Schwierigkeit hier ist, dass diese Zeichenfolgen Zeichen wie Punkte haben können, die als spezielle Zeichen interpretiert werden können, während ich wörtliche Übereinstimmungen benötige.

Was ist der richtige Satz von grep Optionen in der Schleife unten? Oder sollte ich insgesamt einen anderen Befehl verwenden?

while read t 
do 
    grep <OPTIONS> "\t${t}\t" data.txt 
done < strings.txt 
+0

Haben Sie die Manpage gelesen. Es wird erläutert, wie literale Zeichenfolgen abgeglichen werden. – 123

+0

'grep -F' oder' fgrep'. – bishop

+0

Es sieht so aus, als ob sowohl fgrep (als auch grep -F) verhindern, dass das \ t in eine Registerkarte expandiert wird. In vi und in der Shell selbst können Sie^V (drücken Sie Strg-V und dann die Tab-Taste) verwenden, um eine literale Registerkarte in Ihren Code einzufügen, und dann sollte sich fgrep verhalten ... –

Antwort

1

Sobald Sie über einfache regexp Matching (zB etwas Einbeziehung einer bestimmten Spalte/Feld-Targeting), die Sie wollen awk, nicht grep:

awk -F'\t' 'NR==FNR{a[$0];next} $2 in a' strings.txt data.txt 

Die oben tut String-Matching, nicht regexp Matching, so gibt es keine "Sonderzeichen" und ist vollständig darauf ausgerichtet, das gesamte 2. tab-getrennte Feld von data.txt abzugleichen, so dass keine partiellen oder andere falsche Übereinstimmungen möglich sind. Es wird nur genau das, was Sie wollen, übereinstimmen.

Wenn Sie darüber nachdenken, eine Shell-Schleife zu schreiben, um Text zu bearbeiten, lesen Sie https://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice, um einige, aber nicht alle Gründe zu verstehen, warum Sie nicht sollten.

+0

Danke für den Link! Ich bin definitiv schuldig, viel "Loop though text" zu machen. –

+0

Ja, die meisten Leute fangen damit an, weil es zuerst schnell und einfach erscheint, dann im Laufe der Zeit entdeckt man, dass es immens langsam und zerbrechlich ist und keinerlei Vorteile hat Weg... –

1

Verwenden Sie die -f und -F Fahnen zusammen.

grep -f strings.txt -F data.txt 

-f behandelt jede Zeile von strings.txt als separates Muster, während -F String-Matching durchführt, nicht regulären Ausdrücken Anpassung.

+0

Aber wenn ich das tue, gewinnt bekomme ich eine Reihe falscher Übereinstimmungen? Zum Beispiel, wenn ich nach 'foo.' suche, bekomme ich auch' foo. Bar' usw.Das ist der Grund, warum ich die Tabs vor und hinter dem String im 'grep' über –

+0

verwenden möchte. Fügen Sie die Tabs zu' strings.txt' hinzu. – chepner