web-dev-qa-db-ja.com

Grepが2つの単語を1行で検索する

私は、「レモン」と「米」という単語を含む行をフィルターする方法を見つけようとしてきました。 「レモン」または「米」を見つける方法は知っていますが、それらの2つは見つけません。それらは他のテキストの隣にある必要はなく、同じテキスト行にある必要があります。

45
Sebastian

「両方とも同じ行に」とは、「「ライス」の後にランダムな文字が続き、「レモン」が続く、またはその逆」という意味です。

正規表現では、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
60
Florian Diesch

最初の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」一致を検索できます。

26
Aditya

質問は「grep」を要求しますが、単純な「awk」ソリューションを投稿すると役立つと思いました。

awk '/lemon/ && /rice/'

これは、より多くの単語、または「and」以外のブール式で簡単に拡張できます。

21
David B.

任意の順序で一致を見つける別のアイデアは、次を使用することです:

grep with -P(Perl-Compatibility) オプションおよび positive lookahead regex (?=(regex))

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

or代わりに以下を使用できます:

grep -P '(?=.*?rice)(?=.*?lemon)' infile
  • .*?は、パターンが続くオプションの(riceまたはlemon)に0回以上.出現する任意の文字*と一致することを意味します。 ?は、その前のすべてをオプションにします(一致するすべての.*の0回または1回を意味します)

(?=pattern):ポジティブルックアヘッド:ポジティブルックアヘッドコンストラクトは、括弧のペアで、開始括弧の後に疑問符と等号が続きます。

したがって、これはlemonriceの両方をランダムな順序で含むすべての行を返します。また、これは|sと2倍のgrepsの使用を回避します。


外部リンク:
Grepの高度なトピック
ポジティブルックアヘッド–デザイナー向けGREP

11
αғsнιη
grep -e foo -e goo

Fooまたはgooのいずれかの一致を返します

5
netskink

grepに基づく上記の回答のように、awkに基づいていない回答を提供することが認められる場合、次のような単純なPerl行を提案します。

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

検索では、/lemon/i and /rice/iのような一部またはすべての単語の大文字小文字を無視することができます。ほとんどのUnix/Linuxマシンでは、とにかくPerlがインストールされています。

1

Grepパイピングソリューションを自動化するスクリプトを次に示します。

#!/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 "$@"
0
Jeff