Grep ищет два слова в строке

46

Я пытался найти способ отфильтровать строку, в которой есть слова «лимон» и «рис». Я знаю, как найти «лимон» или «рис», но не их обоих. Они не должны быть рядом друг с другом, просто одна и та же строка текста.

Себастьян
источник
1
Чтобы найти все строки внутри файла, вы можете запустить grep в цикле FOR: unix.stackexchange.com/a/462445/43233
Noam Manos

Ответы:

62

«Оба на одной строке» означает «рис», за которым следуют случайные символы, за которыми следует «лимон» или наоборот ».

В регулярном выражении это rice.*lemonили lemon.*rice. Вы можете объединить это, используя |:

grep -E 'rice.*lemon|lemon.*rice' some_file

Если вы хотите использовать обычные регулярные выражения вместо расширенных ( -E), вам необходимо использовать обратную косую черту перед |:

grep 'rice.*lemon\|lemon.*rice' some_file

Для большего количества слов это быстро становится немного длиннее, и обычно проще использовать несколько вызовов grep, например:

grep rice some_file | grep lemon | grep chicken
Флориан Диш
источник
Ваша последняя строка - это соединение, а не дизъюнкция ? Для остроумия: grep riceнаходит строки, содержащие rice. Он подается в grep lemonкоторый будут только строки, содержащие лимон .. и так далее. Принимая во внимание, что ФП - а также ваши предыдущие ответы - разрешают любой из [рис | лимон | курица]
Javadba
Версия сценария: askubuntu.com/a/879253/5696
Джефф
@Florian Diesch - Разум объясняет, почему |нужно сбежать grep? Спасибо!
беглец
1
@fugitive egrepиспользует расширенное регулярное выражение, где |понимается как логика ИЛИ. grepпо умолчанию используется базовое регулярное выражение, где \|OR
Сергей Колодяжный
Как указано в grepman-странице, egrepустарела и должна быть заменена на grep -E. Я взял на себя свободу редактировать ответ соответственно.
десерт
26

Вы можете направить вывод первой команды grep в другую команду grep, которая будет соответствовать обоим шаблонам. Итак, вы можете сделать что-то вроде:

grep <first_pattern> <file_name> | grep <second_pattern>

или же,

cat <file_name> | grep <first_pattern> | grep <second_pattern>

Пример:

Давайте добавим немного содержимого в наш файл:

$ echo "This line contains lemon." > test_grep.txt
$ echo "This line contains rice." >> test_grep.txt
$ echo "This line contains both lemon and rice." >> test_grep.txt
$ echo "This line doesn't contain any of them." >> test_grep.txt
$ echo "This line also contains both rice and lemon." >> test_grep.txt

Что содержит файл:

$ cat test_grep.txt 
This line contains lemon.
This line contains rice.
This line contains both lemon and rice.
This line doesn't contain any of them.
This line also contains both rice and lemon.

Теперь давайте попробуем, что мы хотим:

$ grep rice test_grep.txt | grep lemon
This line contains both lemon and rice.
This line also contains both rice and lemon.

Мы получаем только те строки, где оба шаблона совпадают. Вы можете расширить это и передать вывод в другую команду grep для дальнейших совпадений «И».

Адитья
источник
21

Хотя вопрос требует «grep», я подумал, что было бы полезно опубликовать простое «awk» решение:

awk '/lemon/ && /rice/'

Это может быть легко расширено с помощью большего количества слов или других логических выражений, кроме 'и'.

Дэвид Б.
источник
11

Другая идея для нахождения совпадений в любом порядке:

grep с -P (Perl-Compatibility) опцией и регулярным регулярным выражением(?=(regex)) :

grep -P '(?=.*?lemon)(?=.*?rice)' infile

или вы можете использовать ниже, вместо этого:

grep -P '(?=.*?rice)(?=.*?lemon)' infile
  • Эти .*?средства , соответствующие любые символы , .которые вхождения ноль или более раз , *пока они не являются обязательными с последующим рисунком ( riceили lemon). Он ?делает все необязательным перед ним (означает ноль или один раз из всего совпадения .*)

(?=pattern): Positive Lookahead: положительная конструкция lookahead представляет собой пару круглых скобок, за открывающей скобкой следует знак вопроса и знак равенства.

Таким образом, это вернет все строки с содержит как lemonи riceв случайном порядке. Также это позволит избежать использования |s и удвоенных greps.


Внешние ссылки: Advanced Grep Темы Positive Lookahead - GREP для дизайнеров

αғsнιη
источник
5
grep -e foo -e goo

Вернет совпадения для foo или goo

netskink
источник
1

Если мы признаем, что предоставление ответа, который не grepоснован, является приемлемым, как и вышеупомянутый ответ, основанный на awk, я бы предложил простую perlстроку вроде:

$ perl -ne 'print if /lemon/ and /rice/' my_text_file

Поиск может игнорировать регистр с некоторыми / всеми словами, как /lemon/i and /rice/i. На большинстве машин Unix / Linux в любом случае устанавливается perl и awk.

Жиль Мезоннев
источник
Отказался!!! ;) Потому что это не имеет смысла .. :)
An0n
0

Вот скрипт для автоматизации решения grep piping:

#!/bin/bash

# Use filename if provided as environment variable, or "foo" as default
filename=${filename-foo}

grepand () {
# disable word splitting and globbing
IFS=
set -f
if [[ -n $1 ]]
then
grep -i "$1" ${filename} | filename="" grepand "${@:2}"
else
# If there are no arguments, assume last command in pipe and print everything
cat
fi
}

grepand "$@"
Джефф
источник
1
Это, вероятно, должно быть реализовано с использованием рекурсивной функции, вместо того, чтобы создавать командную строку и evalразбирать ее, что легко ломается
Muru
@muru Не стесняйтесь предложить редактирование. Я ценю комментарий.
Джефф
1
Редактировать это будет слишком сложно, так что я не буду этого делать. Если вы хотите добавить это, вот как я представляю, как это должно выглядеть: paste.ubuntu.com/23915379
muru