4

Все

У меня есть два файла ниже в моей машине Linux, и я хотел найти файл, который содержит "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

Любые указатели будут полезны.

Спасибо Сэнди

3 ответа3

4
    $ 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

Приведенная выше команда рекурсивно анализирует файлы внутри подкаталогов и выводит список файлов, содержащих слово word1 , т.е. file1.txt и file2.txt .

Позже во второй части | xargs grep -L 'word99' , канал отправляет file1.txt и file2.txt качестве входных данных для xargs которые предоставляют их grep качестве аргументов. Затем grep перечисляет файл, который не содержит word99 используя опцию -L , т.е. file1.txt .

Здесь нам нужны xargs поскольку в первой части команды мы получаем file1.txt и file2.txt в качестве вывода на стандартный вывод. Нам нужно проанализировать содержимое этих файлов, а не строки file1.txt и file2.txt .

Следующая команда также дает тот же результат (полностью изменяя способ поиска / исключения строк):

      $ grep -Lr 'word99' * | xargs grep -l 'word1'
      file1.txt
0

Название вашего вопроса говорит "файлы, содержащие" слово. Однако в своем вопросе вы упоминаете «получить имена файлов, содержащие» слово. Это разные вещи. К счастью, они оба довольно просты, поэтому я просто покажу вам оба.

Чтобы найти файлы, содержащие слово:

grep -iR "слово1".

-I говорит игнорировать регистр -R является рекурсивным (имеется в виду поиск по подкаталогам). (Заглавная буква задокументирована OpenBSD и больше похожа на ls, поэтому я предпочитаю, чтобы она была -r.) Период указывает, с чего начать поиск.

Чтобы найти имена файлов, содержащие слово:

находить . -имя " слово1 "

-Iname является нечувствительной к регистру версией "name".

Период указывает, с чего начать поиск. Текущий каталог часто является хорошим выбором.

Примечание. Вы ссылались на « . » В одном из своих примеров. Это было здорово для DOS и, как правило, хорошо для Microsoft Windows, но это действительно плохая привычка для среды Unix. Это заставляет меня думать, что ты знаком с Windows. Хорошо, поймите, что в Windows "НАЙТИ" (или "найти") находит текст в файлах. Unix отличается: "grep" находит текст в файлах, а "find" находит имена файлов.

Теперь, чтобы исключить слово 99 и поместить его в текстовый файл, добавьте следующий текст:

| grep -v word99 >> output.txt

Это ключ трубы, почти всегда Shift-Backslash.

Так, например, если вы хотите сделать оба, используйте:

grep -iR "слово1". | grep -v word99 >> output.txt
находить . имя " слово1 " | grep -v word99 >> output.txt

Часть перед символом канала запускает команду и отправляет вывод в канал в стиле Unix. Затем содержимое отправляется из канала в стандартный ввод следующей команды. grep -v будет смотреть на стандартный ввод, который он получает, и исключать то, что вы хотите. grep -v отправит оставшиеся результаты в стандартный вывод. >> перенаправит стандартный вывод предыдущей команды в конец указанного текстового файла.

Причина, по которой вы не видите документированных опций в команде "find" о том, как исключить текст, заключается в том, что Unix был очень сильно разработан с этой идеей создания более простых программ и использования техники конвейеризации для создания сложных эффектов. В средах Microsoft старый код Microsoft был особенно громоздким при обработке каналов, поэтому программы в основном пытались включить больше функций в каждую программу. С одной стороны, это кажется более простым для конечного пользователя (имея все встроенное), но этому подходу не хватает согласованности. Когда вы используете Unix, не бойтесь трубопровода: как только вы привыкнете к нему, вы можете обнаружить, что он сильно упрощает вещи, но потому что вы можете использовать свои простые инструменты во многих ситуациях, и поэтому вам не нужно переучивать простые приемы снова и снова (для каждой отдельной программы).

0

Это находит файлы, которые содержат word1:

$ find . -name '*.*' -type f -exec grep -q 'word1' {} \; -print
./file1.txt
./file2.txt

Это находит файлы, которые содержат word1 но не word99:

$ 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 {} \; возвращает True для файлов с word99 . Мы положили ! перед ним, чтобы свести на нет возвращаемое значение. Таким образом ! -exec grep -q word99 {} \; возвращает True для файлов, которые не имеют word99 . ! в одинарных кавычках, потому что, если расширение истории включено ! может быть активным персонажем

Заметки:

  1. Параметр -q был добавлен в grep чтобы сделать его тихим. При помощи -q grep установит правильный код выхода, но не отображает совпадающие строки в stdout.

  2. Тест -type f был добавлен для find чтобы он возвращал только имена обычных файлов.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .