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


46

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


1
ファイル内のすべての文字列を検索するには、FORループでgrepを実行できます。unix.stackexchange.com
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だけレモンを含む行を見つけなる...というように。OPは(以前の回答と同様に)[rice | lemon | chicken]のいずれかを許可しています
-javadba

スクリプトのバージョン:askubuntu.com/a/879253/5696
ジェフ

@Florian Diesch-なぜ|逃げる必要があるのかを説明する心grep?ありがとう!
逃亡者

1
@fugitive egrep|、ORロジックとして理解される拡張正規表現を使用します。grep基本的な正規表現、デフォルト\|でOR
Sergiy Kolodyazhnyy

grepのマンページに記載されているとおり、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しましょう。

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

両方のパターンが一致する行のみを取得します。これを拡張し、出力を別のgrepコマンドにパイプして、さらに「AND」一致を検索できます。


21

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

awk '/lemon/ && /rice/'

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


11

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

-P (Perl-Compatibility)オプションと肯定先読み正規表現を使用した(?=(regex)) grep :

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

または、代わりに以下を使用できます:

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

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

両方が含まれているとこれはすべての行を返しますlemonし、riceランダムな順序で。また、これにより|sとdoubled grepの使用が回避されます。


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


5
grep -e foo -e goo

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


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パイピングソリューションを自動化するスクリプトを次に示します。

#!/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簡単に壊れている、それをINGの
muru

@muru編集を提案してください。コメントに感謝します。
ジェフ

1
それを編集するのは書き直しが多すぎるので、私はそれをしません。追加したい場合は、次のようになります。paste.ubuntu.com
muru
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.