異なる行のファイル内の複数の文字列のgrep(つまり、行ベースの検索ではなくファイル全体)?


85

私は言葉を含むファイルをgrepしたいDanskSvenskaまたは Norsk(この後、文字列が含まれていることの情報を持っている私は本当にだけなど、私のワンライナーは少しさらに進ん)使用可能なリターンコードで任意の行に。

私はこのような行を含む多くのファイルを持っています:

Disc Title: unknown
Title: 01, Length: 01:33:37.000 Chapters: 33, Cells: 31, Audio streams: 04, Subpictures: 20
        Subtitle: 01, Language: ar - Arabic, Content: Undefined, Stream id: 0x20, 
        Subtitle: 02, Language: bg - Bulgarian, Content: Undefined, Stream id: 0x21, 
        Subtitle: 03, Language: cs - Czech, Content: Undefined, Stream id: 0x22, 
        Subtitle: 04, Language: da - Dansk, Content: Undefined, Stream id: 0x23, 
        Subtitle: 05, Language: de - Deutsch, Content: Undefined, Stream id: 0x24, 
(...)

これが私が欲しいものの擬似コードです:

for all files in directory;
 if file contains "Dansk" AND "Norsk" AND "Svenska" then
 then echo the filename
end

これを行うための最良の方法は何ですか?1行で実行できますか?

回答:


89

次を使用できます。

grep -l Dansk * | xargs grep -l Norsk | xargs grep -l Svenska

隠しファイルでも検索したい場合:

grep -l Dansk .* | xargs grep -l Norsk | xargs grep -l Svenska

賢い解決策; 注意すべきことの1つ(一般的に言えば、OPが求めていたものとは関係ありません)は、(概念的な)障害が発生した場合でも、全体的な終了コード0になることです。したがって、失敗と成功の判断に関心がある場合は、stdout出力が空かどうかを調べるか、代わりに@EddSteelのアプローチを採用する必要があります。
mklement0 2012

@mklement:Bashでは、PIPESTATUS配列にはパイプラインのメンバーの終了値が含まれています。
追って通知があるまで一時停止します。

@DennisWilliamson知っておくといいですね、ありがとう。別のオプションは、有効にすることですpipefail(一時的に)上のシェルオプション:shopt -so pipefail
mklement0

4
ファイル名にスペースを含めることができる場合は、を使用することgrep -Zxargs -0お勧めします。
ベンシャレノール2013年

1
これにより、ファイルが多い場合に「引数リストが長すぎます」というエラーが発生する可能性があります。
AnnanFay 2015年

23

bashとgrepだけを使用するさらに別の方法:

単一ファイルの場合 'test.txt':

  grep -q Dansk test.txt && grep -q Norsk test.txt && grep -l Svenska test.txt

test.txtファイルに3つすべて(任意の組み合わせ)が含まれている場合に印刷されます。最初の2つのgrepsは何も出力せず(-q)、最後の2つは他の2つが合格した場合にのみファイルを印刷します。

ディレクトリ内のすべてのファイルに対してこれを実行する場合:

   *のfの場合; do grep -q Dansk $ f && grep -q Norsk $ f && grep -l Svenska $ f; 完了

ただし、grepを3回実行する必要はありません。
くるみ2011年

1
パターンを-eと組み合わせることができることは知っていますが、grepだけで接続詞を作成する方法がわかりませんでした。
Edd Steel 2011

1
すごい; re for f ...:スペースなどが埋め込まれたファイル名が正しく処理されるようにするため"$f"だけでなく、(二重引用符で囲む)$fを使用します。
mklement0 2012

@vmpstrに対するこのアプローチの利点は、終了コードがすべての検索語が見つかったかどうかを正しく反映することです。
mklement0 2012

19
grep –irl word1 * | grep –il word2 `cat -` | grep –il word3 `cat -`
  • -i 大文字と小文字を区別しない
  • -r フォルダを介してファイル検索を再帰的にします
  • -l 見つかった単語を含むファイルのリストをパイプします
  • cat - 次のgrepは、リストに渡されたファイルを調べます。

1
これは最も単純で最も簡単な答えであり、非常に役に立ちます。
majick 2017年

9

ファイル内の複数の文字列を異なる行でgrepする方法(パイプ記号を使用):

for file in *;do 
   test $(grep -E 'Dansk|Norsk|Svenska' $file | wc -l) -ge 3 && echo $file
done

ノート:

  1. ""grepで二重引用符を使用する場合は、次のようにパイプをエスケープする必要があります\|。Dansk、Norsk、およびSvenskaを検索します。

  2. 1行に1つの言語しかないことを前提としています。

ウォークスルー:http//www.cyberciti.biz/faq/howto-use-grep-command-in-linux-unix/


Dansk NorskとSvenskaがすべて同じ行に表示されたら、それは失敗しませんか?
vmpstr 2011年

ええ、その場合は失敗します。言語は1行に1つずつ表示されると想定しました。
ダモダランR 2011

があればNorsk、3行でファイルすることもできます。
ベンジャミンW.

6

あなたはackでこれを本当に簡単に行うことができます:

ack -l 'cats' | ack -xl 'dogs'
  • -l:ファイルのリストを返す
  • -x:STDIN(前回の検索)からファイルを取得し、それらのファイルのみを検索します

そして、必要なファイルだけが得られるまで、パイプを続けることができます。


これを試してみると、と書いてありUnknown option: xます。このxフラグをサポートする特定のバージョンのackはありますか?
ハッサン

4
awk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print "0" }' 

その後、シェルで戻り値をキャッチできます

Ruby(1.9+)をお持ちの場合

ruby -0777 -ne 'print if /Dansk/ and /Norsk/ and /Svenka/' file

1
awk END句で、おそらく次のようにします。if (a && b && c) {exit 0} else {exit 1}、またはもっと簡潔にexit !(a && b && c)
glenn jackman 2011年

あなたのルビーソリューションは正しく見えません。これは、すべての検索語を含む段落のみを印刷します。問題は、すべてが同じ段落に表示されていなくても、ファイル(全体として)にすべての単語が含まれているかどうかです。
glenn jackman 2011年

ありがとう。ファイル全体が必要な場合は変更され、-0777
kurumi

4

これにより、複数のファイル内の複数の単語が検索されます。

egrep 'abc|xyz' file1 file2 ..filen 

2
両方の文字列を持つファイルを検索することに加えて、これは「abc」または「xyz」のいずれかのみを持つファイルも検索します。OPは「abc」と「xyz」を含むファイルを要求していたと思います。
クリスワース2018

3

単に:

grep 'word1\|word2\|word3' *

詳細については、この投稿を参照してください


-lフラグを追加しますが、それ以外は、何かが足りない場合を除いて、この答えが最も簡単に思えます。
xdhmoore 2017

はい

3
質問は、3つの用語すべてを含むファイルを返す式について尋ねます。これにより、(3つすべてではなく)3つのうちのいずれかを含む(ファイル名ではなく)行が返されます。
ベンジャミンW.

2

これは、glenn jackmanとkurumiの回答を組み合わせたもので、任意の数の固定単語や固定セットの正規表現ではなく、任意の数の正規表現を使用できます。

#!/usr/bin/awk -f
# by Dennis Williamson - 2011-01-25

BEGIN {
    for (i=ARGC-2; i>=1; i--) {
        patterns[ARGV[i]] = 0;
        delete ARGV[i];
    }
}

{
    for (p in patterns)
        if ($0 ~ p)
            matches[p] = 1
            # print    # the matching line could be printed
}

END {
    for (p in patterns) {
        if (matches[p] != 1)
            exit 1
    }
}

次のように実行します。

./multigrep.awk Dansk Norsk Svenska 'Language: .. - A.*c' dvdfile.dat

2

これが私にとってうまくいったことです:

find . -path '*/.svn' -prune -o -type f -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
./path/to/file1.sh
./another/path/to/file2.txt
./blah/foo.php

これら3つの.shファイルを検索したいだけの場合は、次を使用できます。

find . -path '*/.svn' -prune -o -type f -name "*.sh" -exec gawk '/Dansk/{a=1}/Norsk/{b=1}/Svenska/{c=1}END{ if (a && b && c) print FILENAME }' {} \;
./path/to/file1.sh

1

@kurumiのawkの答えを拡張して、bash関数を次に示します。

all_word_search() {
    gawk '
        BEGIN {
            for (i=ARGC-2; i>=1; i--) {
                search_terms[ARGV[i]] = 0;
                ARGV[i] = ARGV[i+1];
                delete ARGV[i+1];
            }
        }
        {
            for (i=1;i<=NF; i++) 
                if ($i in search_terms) 
                    search_terms[$1] = 1
        }
        END {
            for (word in search_terms) 
                if (search_terms[word] == 0) 
                    exit 1
        }
    ' "$@"
    return $?
}

使用法:

if all_word_search Dansk Norsk Svenska filename; then
    echo "all words found"
else
    echo "not all words found"
fi

1

私は2つのステップでそれをしました。1つのファイルにcsvファイルのリストを作成するこのページのコメントを使用して、必要なものを取得するために2つのスクリプトなしの手順を実行しました。ターミナルに入力するだけです:

$ find /csv/file/dir -name '*.csv' > csv_list.txt
$ grep -q Svenska `cat csv_list.txt` && grep -q Norsk `cat csv_list.txt` && grep -l Dansk `cat csv_list.txt`

それは私が必要としていたことを正確に実行しました-3つの単語すべてを含むファイル名を印刷します。

次のような記号も気に留めてください `' "


1

2つの検索用語のみが必要な場合、おそらく最も読みやすいアプローチは、各検索を実行して結果を交差させることです。

 comm -12 <(grep -rl word1 . | sort) <(grep -rl word2 . | sort)

1

gitがインストールされている場合

git grep -l --all-match --no-index -e Dansk -e Norsk -e Svenska

--no-indexは、Gitによって管理されていない現在のディレクトリ内のファイルを検索します。したがって、このコマンドは、gitリポジトリであるかどうかに関係なく、どのディレクトリでも機能します。


0

私は今日この問題を抱えていましたが、ファイルの名前にスペースが含まれていたため、ここのすべてのワンライナーは私に失敗しました。

これは私が思いついたものです:

grep -ril <WORD1> | sed 's/.*/"&"/' | xargs grep -il <WORD2>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.