Znajdź dokładny ciąg za pomocą grep


9

na przykład mam duży plik tekstowy z wieloma adresami e-mail, używając bash potrzebuję wyszukać / zweryfikować, czy wiadomość e-mail istnieje (lub nie). Czy należy używać (tylko) „kotwic”?

grep '^user1@example.com' text_file

czy są lepsze sposoby? Potrzebuję stworzyć skrypt bash i chciałbym być bezpieczny.


1
Czy e-mail to jedyne słowo w linii?
glenn jackman

w rzeczy samej: plik ma ten format: użytkownik1@example.com example.com/user1
Pol Hallen

1
W takim przypadku użyłbym grep -q '^user1@example\.com\>'- z kotwicą linii na początku i kotwicą końca słowa na końcu.
glenn jackman

Odpowiedzi:


24

Zobacz opcje -F(stały ciąg, w przeciwieństwie do wyrażeń regularnych) i -x(dokładnie: dopasuj całą linię).

grep -Fx user1@example.com text_file

byłoby równoważne z:

grep '^user1@example\.com$' text_file

(pamiętaj, że .jest to operator wyrażeń regularnych, który pasuje do dowolnego znaku).

Użyj tej -qopcji, jeśli chcesz tylko sprawdzić, czy jest taka linia:

grep -Fxq user1@example.com text_file &&
  echo yes, that address is in that file.

Jeśli wiersz do wyszukania i nazwa pliku są zmienne:

grep -Fxqe "$email" < "$file"

Lub

grep -Fxq -- "$email" < "$file"

Nie chcesz:

grep -Fxq "$email" "$file"

jako że mogłoby spowodować problemy, jeśli $emaillub $filezaczęło się -.

Jeśli plik jest posortowany (najlepiej w bieżącej lokalizacji C), możesz przyspieszyć, używając commzamiast grep:

printf '%s\n' user1@example.com | comm -12 - text_file

Przewaga stanie się bardziej oczywista, gdy będziesz mieć kilka adresów e-mail do sprawdzenia (na przykład w innym posortowanym pliku):

comm -12 text_file emails_to_check

byłoby szybsze niż:

grep -Fxf emails_to_check text_file

AFAIK, grep -Fxq -- "$email" "$file"również działa.
vinc17

stephane, dlaczego przeszedłeś z pliku wejściowego (obsługiwanego przez grep) na standardowe wejście za pomocą <readresatora? czy są jakieś zalety?
umläute

@ umläute i vinc17. Jak już powiedziałem, ma to obejmować nazwy plików zaczynające się od -. nawet grep -- "$email" "$file"byłby problem dla pliku o nazwie -(który greptraktuje specjalnie jako oznaczający stdin )
Stéphane Chazelas

6

Aby być maksymalnie wydajnym, chcesz zatrzymać się po znalezieniu pierwszego meczu. Jeśli masz GNU grep, możesz to zrobić:

grep -m 1 '^user1@example\.com$' your_file

Jeśli nie, możesz użyć Perla:

perl -nlE 'say and last if $_ eq q{user1@example.com}' your_file

4
-mjest specyficzny dla GNU. Użyj POSIX, -qjeśli chcesz sprawnie sprawdzić, czy istnieje taka linia.
Stéphane Chazelas

3

Jest tam wiele czeków e-mailowych. Jednym z nich jest:

grep -E -o "\b[a-zA-Z0-9.-]+@[a-zA-Z0-9.-]+\.[a-zA-Z0-9.-]+\b" text_file

Opracować moją odpowiedź.

Używasz ^kotwicy, która wskazuje początek łańcucha. To nie pasuje, jeśli adres e-mail znajduje się gdzieś pomiędzy długim ciągiem.


2
Dzięki. To są ogólne opcje grep do „wyodrębnienia” całego adresu e-mail w pliku. Potrzebuję wyszukać jeden po drugim adres e-mail, używając odczytu EMAIL, a następnie grep, aby to sprawdzić.
Pol Hallen

2

Twoje greppolecenie dopasuje wszystko, co zaczyna się od ^user1@example.com, w tym sam adres e-mail, ale także user1@example.com.spammer.com. ponieważ .jest to znak specjalny w wyrażeniach regularnych pasujący do dowolnego klawisza, powinieneś uciec przed nim jako\.

zakładając, że plik tekstowy zawiera jeden adres w wierszu, użyj:

EMAIL=user1@example\\.com
egrep "^${EMAIL}$" text_file

trailing $sprawi, że linia skończy się po adresie e-mail. Używam również podwójnych cudzysłowów ", ponieważ pozwalają one na używanie zmiennych (w przeciwieństwie do pojedynczych cudzysłowów ')


1
To także pasuje user1@example-com.
Stéphane Chazelas

@ StéphaneChazelas oczywiście masz rację; zaktualizowałem odpowiedź.
umläute

@ umläute Musisz podwoić ukośnik odwrotny. Ale lepiej jest użyć -Fx.
vinc17

@ vinc17, doh; ucieczka bash; w każdym razie tak, zgadzam się, że lepiej jest używać, -Fxale taka jest odpowiedź
Stephane

0

Biorąc pod uwagę ogólne dopasowanie literału / łańcucha ścisłego:

grep -w "search_word" <file>  >  output.txt

#\b shows boundaries over here.

lub,

 grep  "\bsearch_word\b"  <file>  >  output.txt 
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.