如何取得僅包含指定文字的文件的名稱

如何取得僅包含指定文字的文件的名稱

我有一個名為“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」的檔案名,而不是同時包含「cat」和「dog」。
同樣,當我嘗試獲取僅包含“dog”的檔案的名稱時。如果我以相同的方式搜索,那麼它會返回包含“dog”或兩個標籤的檔案名稱。

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

答案1

您可以使用grep兩次:a) 列出所有帶有 的文件cat,然後 b) 篩選出dog包含 的文件。分別使用-l-L,其中-l列出匹配的文件名和-L不匹配的文件名:

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

man grep

-L, --檔案不匹配

抑制正常輸出;相反,列印每個通常不會列印輸出的輸入檔案的名稱。掃描將在第一個匹配處停止。

-l, --帶匹配的文件

抑制正常輸出;相反,列印通常會列印輸出的每個輸入檔案的名稱。掃描將在第一個匹配處停止。

答案2

使用 GNUgrepxargs(無論如何,-R您已經使用的是 GNU擴展,儘管在那裡更好):grep-r

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

將列出至少包含一個cat單字且不包含dog任何單字的檔案 (單字在這種情況下,意思是:「沒有被包圍單字字符「,單字字符是字母數字字元和底線)。替換-w-x以搜尋其全部內容的行 cat/ dog

答案3

如果您想列出包含“cat”但不包含“dog”的文件的名稱,請嘗試使用find和 GNU awk(或任何其他awk支援ENDFILE區塊的文件,因為這是 的 GNU 擴充功能awk):

$ 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

相關內容