Знайдіть точний рядок із грепом


9

Наприклад, у мене великий текстовий файл з багатьма адресами електронної пошти, використовуючи bash, мені потрібен пошук / підтвердження наявності електронної пошти (чи ні). Чи слід використовувати (лише) "якорі"?

grep '^user1@example.com' text_file

або є кращі способи? Мені потрібно створити сценарій bash, і я хотів би бути в безпеці.


1
Є єдине слово в рядку електронної пошти?
glenn jackman

Дійсно: файл має такий формат: user1@example.com example.com/user1
Pol Hallen

1
У такому випадку я б застосував grep -q '^user1@example\.com\>'- з лінійним якорем на початку та з якорем у кінці слова в кінці.
glenn jackman

Відповіді:


24

Перегляньте -F(фіксований рядок, на відміну від регулярного виразу) та -x(точно: відповідність цілому рядку) параметри.

grep -Fx user1@example.com text_file

було б еквівалентом:

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

(пам'ятайте, що .це оператор регулярного вираження, який відповідає будь-якому символу).

Використовуйте -qопцію, якщо ви хочете перевірити, чи є така лінія:

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

Якщо рядок пошуку та ім'я файлу змінні:

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

Або

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

Ви не хочете:

grep -Fxq "$email" "$file"

тому що це може спричинити проблеми, якщо це було $emailабо $fileрозпочато з -.

Якщо файл відсортований (бажано C, у поточному локалі, бажано ), можливо, ви можете прискорити роботу, використовуючи commзамість grep:

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

Перевага стане очевиднішою, коли у вас є кілька електронних адрес для перевірки (наприклад, в іншому відсортованому файлі):

comm -12 text_file emails_to_check

буде швидше, ніж:

grep -Fxf emails_to_check text_file

AFAIK, grep -Fxq -- "$email" "$file"також працює.
vinc17

Стефане, чому ти переключився з файлового вводу (обробляється grep) на stdin, використовуючи <переспрямовувач? чи є якісь переваги?
umläute

@ umläute та vinc17. Як я вже сказав, це покриття для імен файлів, починаючи з -. навіть grep -- "$email" "$file"буде проблема для файлу під назвою -(який grepтрактує спеціально як значення stdin )
Stéphane Chazelas

6

Щоб бути максимально ефективним, ви хочете зупинитися після того, як буде знайдено перший матч. Якщо у вас є GNU grep, ви можете це зробити:

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

Якщо цього немає, ви можете використовувати Perl:

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

4
-mє специфічним для GNU Використовуйте POSIX, -qякщо хочете ефективно перевірити, чи існує така лінія.
Stéphane Chazelas

3

Там багато перевірок електронної пошти. Одне з них:

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

Сформулювати свою відповідь.

Ви використовуєте ^якір, який вказує на початок рядка. Це не збігатиметься, якщо адреса електронної пошти знаходиться десь між довгою рядком.


2
Дякую. Це загальні параметри грепу для "вилучення" всієї адреси електронної пошти всередині файлу. Мені потрібно шукати одну за однією адресою електронної пошти, використовуючи читання EMAIL, а потім за допомогою grep, щоб перевірити її.
Пол Галлен

2

ваша grepкоманда буде відповідати всьому, з чого починається ^user1@example.com, включаючи саму електронну адресу, але також user1@example.com.spammer.com. оскільки .це спеціальний символ у регулярних виразах, який відповідає будь-якій клавіші, вам слід уникати цього\.

припускаючи, що ваш текстовий файл містить одну адресу на рядок, використовуйте:

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

трейлінг $переконається, що рядок закінчується після електронної адреси. Я також використовую подвійні лапки ", оскільки вони дозволяють використовувати змінні (на відміну від одинарних лапок ')


1
Це теж відповідає user1@example-com.
Stéphane Chazelas

@ StéphaneChazelas ви, звичайно, праві; оновив відповідь.
umläute

@ umläute Вам потрібно подвоїти нахил внизу. Але краще використовувати -Fx.
vinc17

@ vinc17, да; баш втеча; так чи інакше, я погоджуюся, що краще використовувати, -Fxале це відповідь Стефана :-)
umläute

0

З огляду на загальну буквальну / точну відповідність рядків:

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

#\b shows boundaries over here.

або,

 grep  "\bsearch_word\b"  <file>  >  output.txt 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.