指定されたテキストのみを含むファイルの名前を取得する方法

指定されたテキストのみを含むファイルの名前を取得する方法

「labels」という名前のディレクトリがあり、その中に「cat」または「dog」、あるいはその両方のラベルが別々の行に書かれたテキスト ファイルがあります。labels
ディレクトリ内のファイルの内容は次のとおりです。

cat labels/1.txt
cat

cat labels/2.txt
dog

cat labels/3.txt
cat  
dog

ラベル「cat」のみを含むファイルの名前を取得したいです。次のコマンドを試しました:

ls labels | grep -Rwl "cat"   
labels/1.txt  
labels/3.txt  

しかし、このコマンドは、「cat」または両方を含むファイル名を返します。しかし、私の要件は、「cat」と「dog」の両方ではなく、「cat」のみを含むファイル名を取得することです。
同様に、「dog」のみを含むファイル名を取得しようとすると、同じ方法で検索すると、「dog」または両方のラベルを含むファイル名が返されます。

ls labels | grep -Rwl "dog"
labels/2.txt  
labels/3.txt  

答え1

を 2 回使用できますgrep。a) を使用して を含むすべてのファイルを一覧表示しcat、次に b) を使用して を含むファイルを除外しますdog-lと を-Lそれぞれ使用します。 は、-l一致するファイル名と-L一致のないファイル名を一覧表示します。

grep -L 'dog' $(grep -l 'cat' <list of files>)

見るman grep

-L, --一致しないファイル

通常の出力を抑制し、代わりに、通常は出力が印刷されない各入力ファイルの名前を印刷します。スキャンは最初の一致で停止します。

-l, --一致するファイル

通常の出力を抑制し、代わりに、通常出力が印刷される各入力ファイルの名前を印刷します。スキャンは最初の一致で停止します。

答え2

GNU およびgrep(xargsすでに-R使用しているのはいずれにせよ GNUgrep拡張機能ですが、-rここでは が推奨されます) を使用する場合:

grep -rwlZ cat labels/ | xargs -r0 grep -wL dog

少なくとも1つのcat単語を含み、dog単語を含まないファイルをリストします(言葉その文脈では「囲まれていない単語の文字"、単語の文字英数字とアンダースコアを含む)-wに置き換えて-x、内容全体が cat/ dog.

答え3

「cat」は含まれているが「dog」は含まれていないファイルの名前を一覧表示したい場合は、findと GNU (または の GNU 拡張であるため、ブロックをサポートするawkその他の) を使用して、次のように実行してください。awkENDFILEawk

$ find labels/ -type f -exec awk -v IGNORECASE=1 '
    /\<cat\>/ { cat = 1 };
    /\<dog\>/ { dog = 1 };

    ENDFILE {
      if (cat == 1 && dog == 0) {
        print FILENAME
      };
      cat = 0;
      dog = 0;
    }' {} +
labels/file1.txt

perlまたは、代わりに以下を使用することもできますawk:

$ find labels/ -type f -exec perl -l -n -e  '
    $cat = 1 if m/\bcat\b/i;
    $dog = 1 if m/\bdog\b/i;
    if (eof) {
      print $ARGV if ($cat && ! $dog);
      $cat=0;
      $dog=0;
    }' {} +
labels/file1.txt

上記の awk と perl の両方のバージョンからの出力は、labels/サブディレクトリ内の次のファイルを使用して生成されました。

$ tail labels/*
==> labels/file1.txt <==
cat

==> labels/file2.txt <==
dog

==> labels/file3.txt <==
cat
dog

labels/file1.txtこれは、「cat」を含み、「dog」を含まない唯一のファイルであるため、印刷される唯一のファイル名です。

答え4

for f in *; do diff -q <(sort -u "$f") <(echo cat) >/dev/null && echo "$f"; done

関連情報