Греп, поиск двух слов в строке

41

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

    
задан Sebastian 26.02.2015 в 22:13
источник

7 ответов

54

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

В регулярном выражении 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
    
ответ дан Florian Diesch 26.02.2015 в 22:29
источник
25

Вы можете передать вывод первой команды 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 то, что хотим:

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

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

    
ответ дан Aditya 26.02.2015 в 22:31
19

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

awk '/lemon/ && /rice/'

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

    
ответ дан David B. 27.02.2015 в 04:49
11

Еще одна идея найти совпадения в любом порядке:

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

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

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

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

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

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

Внешние ссылки:
Расширенные темы Grep
Позитивный Lookahead - GREP для дизайнеров

    
ответ дан sddgob 27.02.2015 в 00:05
4
grep -e foo -e goo

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

    
ответ дан netskink 24.07.2017 в 16:46
1

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

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

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

    
ответ дан Gilles Maisonneuve 25.08.2018 в 21:51
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 "[email protected]"
    
ответ дан Jeff 03.02.2017 в 02:21