Команда оболочки для поиска файлов, содержащих одно слово, но не второе слово
Все
У меня есть два файла ниже в моей машине 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 ответа
$ 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 -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, не бойтесь трубопровода: как только вы привыкнете к нему, вы можете обнаружить, что он сильно упрощает вещи, но потому что вы можете использовать свои простые инструменты во многих ситуациях, и поэтому вам не нужно переучивать простые приемы снова и снова (для каждой отдельной программы).
Это находит файлы, которые содержат 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
, !
в одинарных кавычках, потому что, если расширение истории включено, !
может быть активным персонажем
Заметки:
-q
опция была добавлена вgrep
чтобы это было тихо. С-q
grep установит правильный код выхода, но не отображает совпадающие строки в stdout.-type f
тест был добавлен вfind
так что он возвращает только имена обычных файлов.