Команда оболочки для поиска файлов, содержащих одно слово, но не второе слово

1046
Sandeep K Gujje

Все

У меня есть два файла ниже в моей машине 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 

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

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

4

3 ответа на вопрос

4
Santios
 $ 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 
`grep -r… *` почти всегда лучше пишется как `grep -r… .`. Версия звездочки становится ужасной, если в текущем каталоге слишком много файлов и т. Д. Eric 7 лет назад 1
0
John1024

Это находит файлы, которые содержат 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чтобы сделать это тихо. С помощью -qgrep будет задан правильный код выхода, но он не отображает совпадающие строки в stdout.

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

Спасибо Джону за ответ, но что, если мне придется выполнить поиск по всем папкам (рекурсивно). Погода добавляет просто "-r" работает? Sandeep K Gujje 7 лет назад 0
@SandeepKGujje `find` сам выполняет рекурсивный поиск по всем папкам. John1024 7 лет назад 0
0
TOOGAM

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

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

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, не бойтесь трубопровода: как только вы привыкнете к нему, вы можете обнаружить, что он сильно упрощает вещи, но потому что вы можете использовать свои простые инструменты во многих ситуациях, и поэтому вам не нужно переучивать простые приемы снова и снова (для каждой отдельной программы).

Похожие вопросы