Как получить имена файлов, содержащих только указанный текст

Как получить имена файлов, содержащих только указанный текст

У меня есть каталог с именем "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дважды: а) для перечисления всех файлов с cat, затем б) отсеять dogте, которые содержат . Используйте -lи -L, соответственно, где -lперечисляет имена файлов с совпадениями и -Lимена файлов без совпадений:

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

Видеть man grep:

-L, --files-without-match

Подавить нормальный вывод; вместо этого вывести имя каждого входного файла, из которого обычно не печатается вывод. Сканирование остановится при первом совпадении.

-l, --files-with-matches

Подавить нормальный вывод; вместо этого вывести имя каждого входного файла, из которого вывод обычно печатался бы. Сканирование остановится при первом совпадении.

решение2

С GNU grepи xargs( -Rкоторый вы уже используете, grepв любом случае является расширением GNU, хотя -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

Связанный контент