web-dev-qa-db-ja.com

grepを使ってstring1とstring2の両方を含む行を一致させるにはどうすればいいですか?

2つの異なる文字列を含む行を一致させるためにgrepを使用しようとしています。私は以下を試しましたが、これはstring1またはのどちらかを含む行と一致します。 )string2これは私が欲しいものではありません。

grep 'string1\|string2' filename

それでは、両方の文字列を含む行だけをgrepと照合するにはどうすればよいでしょうか。

190
hearsaxas

あなたはgrep 'string1' filename | grep 'string2'を使うことができます

または、grep 'string1.*string2\|string2.*string1' filename

163
dheerosaur

私はこれがあなたが探していたものだと思います:

grep -E "string1|string2" filename

私はそのような答えを考えています:

grep 'string1.*string2\|string2.*string1' filename

両方が存在する場合にのみ一致し、一方または他方または両方には一致しません。

193
user45949

複数の-eオプションを指定するだけです。

 -e pattern, --regexp=pattern
         Specify a pattern used during the search of the input: an input
         line is selected if it matches any of the specified patterns.
         This option is most useful when multiple -e options are used to
         specify multiple patterns, or when a pattern begins with a dash
         (`-').

したがって、コマンドは次のようになります。

grep -e "string1" -e "string2" filename

注:上記でBSD版のマニュアルを引用しましたが、Linuxでも 同じです

44
Tony

すべての単語を含むファイルを任意の順序でどこでも検索するには、次の手順を実行します。

grep -ril \'action\' | xargs grep -il \'model\' | xargs grep -il \'view_type\'

最初のgrepは再帰的検索(r)をキックオフします。大文字と小文字の区別(i)を無視し、ファイル内の任意の場所('action')と一致するファイル名(l)をリスト(表示)します。

後続のgrepsは他の用語を検索し、大文字と小文字を区別しないで一致するファイルをリストします。

あなたが得ることになるファイルの最終的なリストは、ファイル内の任意の場所でこれらの用語を含むものになります。

26
Kinjal Dixit

限定されたgrep正規表現に対して-Pオプションを指定したPerlがある場合は、

grep -P '(?=.*string1)(?=.*string2)'

これには、重複する文字列を扱うという利点があります。 Perlgrepとして使用する方がやや簡単です。これはandロジックをより直接的に指定できるからです。

Perl -ne 'print if /string1/ && /string2/'
14
tchrist

あなたの方法はほとんど良かった、-wがないだけ

grep -w 'string1\|string2' filename
12
Leo

あなたはこのようなことを試すことができます:

(pattern1.*pattern2|pattern2.*pattern1)
7
John Dorn

正規表現の|演算子は、またはを意味します。つまり、string1またはstring2のどちらかが一致します。あなたがすることができます:

grep 'string1' filename | grep 'string2'

これは最初のコマンドの結果を2番目のgrepに送ります。それはあなたに両方にマッチする行だけを与えるべきです。

5
martineno

そして、人々がPerlとpythonを示唆し、そして複雑なシェルスクリプトを提案したように、ここで簡単なawkアプローチ:

awk '/string1/ && /string2/' filename

受け入れられた答えに対するコメントを見たことはありません:いいえ、これは複数行にはなりません。しかし、それは質問の作者が求めたものでもありません。

3
tink

6個のスペースで始まり、以下で終わる行が見つかりました。

 cat my_file.txt | grep
 -e '^      .*(\.c$|\.cpp$|\.h$|\.log$|\.out$)' # .c or .cpp or .h or .log or .out
 -e '^      .*[0-9]\{5,9\}$' # numers between 5 and 9 digist
 > nolog.txt
2
Cristian

ファイルtestfileで複数の単語の数を見つける必要があるとしましょう。それに取り組む2つの方法があります

1)正規表現のマッチングパターンでgrepコマンドを使う

grep -c '\<\(DOG\|CAT\)\>' testfile

2)egrepコマンドを使用

egrep -c 'DOG|CAT' testfile 

Egrepを使用すると、式を気にする必要はなく、単語をパイプ区切り文字で区切るだけで済みます。

2
Amit Singh
grep ‘string1\|string2’ FILENAME 

GNU grepバージョン3.1

2
tilikoom
grep -i -w 'string1\|string2' filename

これは、単語の完全一致と大文字と小文字を区別しない単語の一致のために機能します。

1
Saurabh

Grepしたい文字列をファイルに入れる

echo who    > find.txt
echo Roger >> find.txt
echo [44][0-9]{9,} >> find.txt

次に-fを使って検索します。

grep -f find.txt BIG_FILE_TO_SEARCH.txt 
1
Tim Seed
grep '(string1.*string2 | string2.*string1)' filename

任意の順序でstring1とstring2の行を取得します

1
James

git grep

これは、 git grep に複数のパターンを使った構文です。

git grep --all-match --no-index -l -e string1 -e string2 -e string3 file

また、パターンを--and--or--notなどのブール式と組み合わせることもできます。

man git-grepを調べてください。


--all-match複数のパターン表現を与えるとき、このフラグはそれらのすべてにマッチする行を持つファイルにマッチを制限するように指定されます

--no-indexGitで管理されていないカレントディレクトリ内のファイルを検索します。

-l/--files-with-matches/--name-onlyファイルの名前だけを表示します。

-e次のパラメータはパターンです。デフォルトは基本的な正規表現を使うことです。

考慮すべき他のパラメータ:

--threads使用するgrepワーカースレッドの数。

-q/--quiet/--silent一致した行を出力しません。一致した場合は、ステータス0で終了します。

パターンタイプを変更するには、-G/--basic-regexp(デフォルト)、-F/--fixed-strings-E/--extended-regexp-P/--Perl-regexp-f fileなどを使用することもできます。

関連する

または操作については、以下を参照してください。

0
kenorb

複数行一致の場合

echo -e "test1\ntest2\ntest3" |tr -d '\n' |grep "test1.*test3"

または

echo -e "test1\ntest5\ntest3" >tst.txt
cat tst.txt |tr -d '\n' |grep "test1.*test3\|test3.*test1"

改行文字を削除するだけでうまくいきます。

0
Aquarius Power

私はよくあなたと同じ問題に出くわします、そして私はただスクリプトの一部を書きました:

function m() { # m means 'multi pattern grep'

    function _usage() {
    echo "usage: COMMAND [-inH] -p<pattern1> -p<pattern2> <filename>"
    echo "-i : ignore case"
    echo "-n : show line number"
    echo "-H : show filename"
    echo "-h : show header"
    echo "-p : specify pattern"
    }

    declare -a patterns
    # it is important to declare OPTIND as local
    local ignorecase_flag  filename linum header_flag colon result OPTIND

    while getopts "iHhnp:" opt; do
    case $opt in
        i)
        ignorecase_flag=true ;;
        H)
        filename="FILENAME," ;;
        n)
        linum="NR," ;;
        p)
        patterns+=( "$OPTARG" ) ;;
        h)
        header_flag=true ;;
        \?)
        _usage
        return ;;
    esac
    done

    if [[ -n $filename || -n $linum ]]; then
    colon="\":\","
    fi

    shift $(( $OPTIND - 1 ))

    if [[ $ignorecase_flag == true ]]; then
    for s in "${patterns[@]}"; do
            result+=" && s~/${s,,}/"
    done
    result=${result# && }
    result="{s=tolower(\$0)} $result"
    else
    for s in "${patterns[@]}"; do
            result="$result && /$s/"
    done
    result=${result# && }
    fi

    result+=" { print "$filename$linum$colon"\$0 }"

    if [[ ! -t 0 ]]; then       # pipe case
    cat - | awk "${result}"
    else
    for f in "$@"; do
        [[ $header_flag == true ]] && echo "########## $f ##########"
        awk "${result}" $f
    done
    fi
}

使用法:

echo "a b c" | m -p A 
echo "a b c" | m -i -p A # a b c

あなたが好きならあなたはそれを.bashrcに入れることができます。

0
ruanhao

あなたはこのようなgrepを持つべきです:

$ grep 'string1' file | grep 'string2'
0
Raghuram

これにはgrepを使わないでください。代わりにawkを使ってください。 grepで2つの正規表現R1とR2を一致させるには、次のようになると思います。

grep 'R1.*R2|R2.*R1'

awkの間にそれはあるだろう:

awk '/R1/ && /R2/'

しかし、R2R1と重なる、またはそのサブセットである場合はどうなりますか。そのgrepコマンドは、awkコマンドでは機能しません。 theheatを含む行を見つけたいとしましょう。

$ echo 'theatre' | grep 'the.*heat|heat.*the'
$ echo 'theatre' | awk '/the/ && /heat/'
theatre

そのためには2つのgrepsと1つのパイプを使用する必要があります。

$ echo 'theatre' | grep 'the' | grep 'heat'
theatre

もちろん、実際にそれらを別々にすることを要求していた場合は、grepで使用したのと同じ正規表現をawkに書き込むことができ、すべての可能な順序で正規表現を繰り返すことを含まない代替のawkソリューションがあります。

それを脇に置いて、もしあなたが3つの正規表現R1、R2、そしてR3と一致するようにあなたの解決策を拡張したいとしたらどうでしょうか。 grepでは、それはこれらの悪い選択の1つになるでしょう:

grep 'R1.*R2.*R3|R1.*R3.*R2|R2.*R1.*R3|R2.*R3.*R1|R3.*R1.*R2|R3.*R2.*R1' file
grep R1 file | grep R2 | grep R3

awkでは、簡潔で、明白で、単純で、効率的なものになります。

awk '/R1/ && /R2/ && /R3/'

さて、あなたが実際に正規表現R1とR2の代わりにリテラル文字列S1とS2をマッチさせたいとしたらどうでしょうか? grepを一度呼び出すだけではできません。grepを呼び出す前に、すべてのREメタ文字をエスケープするコードを書く必要があります。

S1=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R1')
S2=$(sed 's/[^^]/[&]/g; s/\^/\\^/g' <<< 'R2')
grep 'S1.*S2|S2.*S1'

または2グレップとパイプをもう一度使用します。

grep -F 'S1' file | grep -F 'S2'

これはやはり悪い選択ですが、awkでは単にregexp演算子の代わりに文字列演算子を使用します。

awk 'index($0,S1) && index($0.S2)'

では、行ではなく段落で2つの正規表現を一致させたい場合はどうしますか。 grepではできない、awkではささいなこと:

awk -v RS='' '/R1/ && /R2/'

ファイル全体ではどうでしょうか。ここでも、awkではgrepでささいなことをすることはできません(今回は簡潔にするためにマルチ文字RSにGNU awkを使用しますが、他のawkではこれ以上コードを使用しません。あなたが知っているcharは、RSが同じことをするための入力には含まれません。

awk -v RS='^$' '/R1/ && /R2/'

そのため、行、段落、またはファイル内で複数の正規表現または文字列を検索する場合は、grepを使用しないでください。awkを使用してください。

0
Ed Morton