すべて
Linuxマシンに以下の2つのファイルがあり、「Word1」を含み「Word99」を含まないファイルを見つけたいと思いました。
file1.txt
Word1
Word2
Word3
Word4
Word5
file2.txt
Word1
Word2
Word3
Word99
「Word1」を含むファイルに対して以下のコマンドを使用していますが、「Word1」を含むが「Word99」を含まないファイル名を取得するように変更する方法に関する情報が見つかりませんでした
find . -name '*.*' -exec grep -r 'Word1' {} \; -print > output.txt
どんなポインタも役に立ちます。
サンディありがとう
$ grep -lr 'Word1' * | xargs grep -L 'Word99'
file1.txt
どこ:
-l, --files-with-matches
Only the names of files containing selected lines are written
to standard output.
-R, -r, --recursive
Recursively search subdirectories listed.
-L, --files-without-match
Only the names of files not containing selected lines are written
to standard output.
パイプの前のコマンドの最初の部分では、次のようになります。
$ grep -lr 'Word1' *
file1.txt
file2.txt
上記のコマンドは、サブディレクトリ内のファイルを再帰的に解析し、Word Word1
、つまりfile1.txt
とfile2.txt
を含むファイルを一覧表示します。
後の2番目の部分| xargs grep -L 'Word99'
で、パイプはfile1.txt
とfile2.txt
を入力としてxargs
に送信し、引数としてgrep
に提供します。次に、grep
は、Word99
オプション、つまり-L
を使用して、file1.txt
を含まないファイルを一覧表示します。
コマンドの最初の部分で、stdoutの出力としてfile1.txt
とfile2.txt
を取得するため、ここではxargs
が必要です。文字列file1.txt
およびfile2.txt
ではなく、これらのファイルの内容を解析する必要があります。
次のコマンドでも同じ結果が得られます(文字列の検索/除外の方法が逆になります)。
$ grep -Lr 'Word99' * | xargs grep -l 'Word1'
file1.txt
質問のタイトルには、単語を「含むファイル」と記載されています。しかし、あなたの質問では、Wordを「含むファイル名を取得する」と述べています。これらは別のものです。幸い、どちらもかなり単純なので、両方を簡単に紹介します。
Wordを含むファイルを検索するには:
grep -iR "Word1"。
-iは大文字と小文字を区別しないように言います。 -Rは再帰的です(サブディレクトリが検索されることを意味します)。 (大文字はOpenBSDによって文書化されており、lsに似ているので、-rよりも優先します。)ピリオドは、どこから検索を開始するかを指定します。
Wordを含むファイル名を検索するには:
見つける。 -iname "Word1"
-inameは、大文字と小文字を区別しないバージョンの「name」です。
期間は、どこから探し始めるかを指定します。多くの場合、現在のディレクトリが適切な選択です。
注:例の1つで「。 "」を参照しました。これはDOSには最適で、通常はMicrosoft Windowsには適していますが、Unix環境には非常に悪い習慣です。それを見ると、あなたはWindowsに精通していると思います。 Windowsでは、「FIND」(または「find」)がファイル内のテキストを検索することを理解してください。 Unixは異なります。「grep」はファイル内のテキストを検索し、「find」はファイル名を検索します。
ここで、Word 99を除外し、それをテキストファイルに配置するには、次のテキストを追加します。
| grep -v Word99 >> output.txt
これはパイプキーであり、ほとんどの場合Shift-Backslashです。
したがって、例として、両方を実行したい場合は、次を使用します。
grep -iR "Word1"。 | grep -v Word99 >> output.txt
検索。 -iname "Word1" | grep -v Word99 >> output.txt
パイプ文字の前の部分はコマンドを実行し、出力をUnixスタイルのパイプに送信します。次に、コンテンツはパイプから次のコマンドの標準入力に送信されます。 grep -vは、受け取った標準入力を調べて、必要なものを除外します。 grep -vは、残りの結果を標準出力に送信します。 >>は、前のコマンドの標準出力を指定されたテキストファイルの末尾にリダイレクトします。
テキストを除外する方法について、「find」コマンドに文書化されたオプションが表示されない理由は、Unixが非常に重く設計されており、より単純なプログラムを作成し、パイピング技術を使用して精巧な効果を生み出すという考えに基づいているためです。 Microsoft環境では、古いMicrosoftコードはパイプ処理が特に面倒だったため、プログラムは基本的に各プログラムにより多くの機能を組み込むことを試みました。一方で、これはエンドユーザー(すべてが組み込まれている)にとっては簡単に思えますが、そのアプローチには一貫性がありません。 Unixを使用しているときは、パイピングを恐れないでください。慣れると、作業が大幅に簡素化されることに気付くかもしれませんが、多くの状況で簡単なツールを使用できるため、必要ありません。簡単なテクニックを何度も何度も再学習します(異なるプログラムごとに)。
これにより、Word1
を含むファイルが検索されます。
$ find . -name '*.*' -type f -exec grep -q 'Word1' {} \; -print
./file1.txt
./file2.txt
これにより、Word1
を含むがnotWord99
を含むファイルが検索されます。
$ find . -name '*.*' -type f -exec grep -q 'Word1' {} \; '!' -exec grep -q 'Word99' {} \; -print
./file1.txt
出力をファイルに保存するには:
find . -name '*.*' -type f -exec grep -q 'Word1' {} \; '!' -exec grep -q 'Word99' {} \; -print >output.txt
テスト-exec grep -q Word99 {} \;
は、Word99
のファイルに対してTrueを返します。その前に!
を付けて、戻り値を無効にします。したがって、! -exec grep -q Word99 {} \;
は、Word99
を持つnotファイルに対してTrueを返します。 !
は一重引用符で囲まれています。これは、履歴拡張がオンになっている場合、!
がシェルアクティブ文字になる可能性があるためです。
ノート:
-q
オプションがgrep
に追加され、静かになりました。 -q
を使用すると、grepは正しい終了コードを設定しますが、stdoutに一致する行を表示しません。
-type f
テストがfind
に追加され、通常のファイルの名前のみが返されるようになりました。