Как использовать команду «grep» для поиска текста, включая подкаталоги

373

Я хочу найти все файлы, которые содержат определенную строку текста. Команда grepработает, но я не знаю, как использовать ее для каждого каталога (я могу сделать это только для моего текущего каталога). Я пытался читать man grep, но это не помогло.

Smile.Hunter
источник
grep -RIn <yor pattern> * Будет искать из текущих каталогов во всех текстовых файлах. Не уверен, как сделать мой поиск рекурсивно в шаблонах файлов, таких как * .C, только с grep
1
Подстановочный --include="*.C"знак с параметром @ user311346, спасибо @Lekensteyn.
Боб Стейн
Используйте комбинацию find и grep для рекурсивного поиска файлов по строке в текущем и всех подкаталогах. Проверьте это wilddiary.com/find-files-conisting-my-text
Дрона

Ответы:

487

Было бы лучше использовать

grep -rl "string" /path

где

  • -r(или --recursive) опция используется для обхода также всех подкаталогов /path, тогда как
  • -l(или --files-with-matches) опция используется только для печати имен файлов совпадающих файлов, но не совпадающих строк (это также может повысить скорость, учитывая, что grepпри первом совпадении прекращается чтение файла с этой опцией).
enzotib
источник
13
На самом деле, если «строка» является текстовым шаблоном для поиска, лучше использовать эту функцию, в противном случае кто-то может столкнуться с проблемами, когда строка содержит точку или специальный символ, который имеет значение в регулярных выражениях, а не просто точка, которая должна быть найдена в виде строки. , как есть. Тогда я бы использовал -rlFпереключатели -Fдля «фиксированной строки» (а не регулярное выражение - например). Конечно, если в задании использовалось регулярное выражение, то извините. Конечно, та же самая теория без -r, я часто вижу, что люди предполагают, что grep ищет «текст», и это может вызвать проблемы, которые, в частности, означают что-то вроде регулярного выражения.
ЛГБ
4
Существует также -iфлаг, который игнорирует регистр.
Марко Чеппи
3
Я хотел бы только показать --recursiveвариант, есть множество вариантов и сценариев использования, о которых можно говорить. Я начал с принятого ответа @dmityugov и изменил, чтобы работать без find.
энзотиб
1
@NN: сделано :-)
энзотиб
3
@ScottBiggs: с опцией--include '*.h'
энзотиб
167

Если вы ищете совпадения строк в файлах, моя любимая команда:

grep -Hrn 'search term' path/to/files
  • -H вызывает печать имени файла (подразумевается при поиске нескольких файлов)
  • -r выполняет рекурсивный поиск
  • -n вызывает печать номера строки

path/to/filesможно .искать в текущем каталоге

Другие варианты, которые я считаю очень полезными:

  • -Iигнорировать двоичные файлы (дополнение: -aобрабатывать все файлы как текст)
  • -Fтрактовать search termкак буквальное, а не регулярное выражение
  • -i выполнить поиск без учета регистра
  • --color=alwaysзаставлять цвета, даже когда пронзает less. Чтобы сделать lessцвета поддержки, вам нужно использовать -rопцию:

    grep -Hrn search . | less -r
    
  • --exclude-dir=dirполезно для исключения каталогов, как .svnи .git.

Пример вывода

Lekensteyn
источник
13
-Hв папке является избыточным, если существует более одного файла, что является вероятным. На самом деле, на странице -H, --with-filename: Print the file name for each match. This is the default when there is more than one file to search.
руководства
Я не знал этого, он всегда работал так, как я ожидал. Это моя команда по умолчанию при поиске файлов.
Лекенштейн
1
Есть ли способ рассматривать файлы с расширением, скажем, .a (и объединять это с -r)?
user2413
6
@ user2413 Попробуй--include '*.*'
Лекенштейн
1
@alper Trygrep --exclude='*~' ...
Лекенштейн
24

Я считаю, что вы можете использовать что-то вроде этого:

find /path -type f -exec grep -l "string" {} \;

Объяснение из комментариев

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

  • -type f указывает, что он должен обрабатывать только файлы, а не каталоги и т. д.
  • -exec grepуказывает, что для каждого найденного файла он должен выполнить команду grep, передав ей имя файла в качестве аргумента, заменив {}его именем файла
dmityugov
источник
3
Просто для тех, кто не знает, добавление -name '*.py'ограничивает совпадения для файлов, заканчивающихся на «.py».
Даниэль Ф
Мне нравится, что это распространяется на клиентов, которые не внедрили -R в своей команде grep.
Aviose
Если вы хотите, чтобы совпадающая строка и имя файла были напечатаны, сделайте exec вроде:... -exec bash -c 'grep -r "mystring" {} && echo {}' \;
Donn Lee
каково относительное перфект к использованию непосредственно grep?
Джонатан
19

Моя команда по умолчанию

grep -Rin string *

Я использую Капитолий 'R', потому что lsиспользует его для рекурсии. Поскольку grep принимает и то и другое, нет причин не использовать его.

РЕДАКТИРОВАТЬ: согласно HVNSweeting, по-видимому, -Rбудет следовать символические ссылки, где, как -rне будет.

user606723
источник
1
Для поиска в скрытых файлах также запустите shopt -s dotglob(запомните -sкак «set»). Будьте осторожны при удалении файлов. Если вы включили dotglob, rm -r *удаляет все в текущем каталоге , а также каталог над ним, потому что ..совпадает. Чтобы отключить dotglob, используйте shopt -u dotglob(«unset»). Изменения носят временный характер, это относится только к текущей оболочке.
Лекенштейн
Я забыл об этом. Есть ли способ установить его для одной строки? что-то вроде shopt -s dotglob & <grep cmd> & shopt -y dotglobтолько удобнее? Таким образом, нам не придется беспокоиться о его сбросе
user606723
Кроме того, это, вероятно, легче использовать grep -Rin string .в большинстве этих случаев. Я просто использую *, потому что это кажется более естественным.
user606723
1
если вы делаете рекурсивный grep, тогда вы можете просто начать с "." вместо "*". не нужен дотглоб.
Михал Шрайер
1
проголосуйте за это, одна вещь не упоминается на man-странице, это Rбудет следовать символическим ссылкам, rне
HVNSweeting
12

Если вы хотите попробовать что-то новое, попробуйте ack. Команда для рекурсивного поиска в текущем каталоге string:

ack string

Установка довольно проста:

curl http://betterthangrep.com/ack-standalone > ~/bin/ack && chmod 0755 !#:3

(При условии, что у вас уже есть каталог, ~/binи он предпочтительно находится у вас PATH.)

Конрад Рудольф
источник
2
Или просто apt-get установите ack-grep (и добавьте псевдоним ack = ack-grep к вашему .bashrc)
markijbema
Что делают последние параметры chmodкоманды? Они специфичны для chmodили связаны с bash ( !#:3часть)?
Эллиот Дарфинк
@ElliottDarfink Вот с помощью Bash - функции История - !это указатель события . Они довольно мощные, чтобы избежать повторений. !#:3ссылается на третий токен командной строки, то есть ~/bin/ackв этом случае.
Конрад Рудольф
4

Команда rgrep предназначена для такой необходимости.

Если нет в наличии, вы можете получить это так

mkdir -p ~/bin
cd ~/bin
wget http://sdjf.esmartdesign.com/files/rgrep
chmod +x rgrep

Вы можете напрямую установить параметры по умолчанию в grep, как описано выше.

Я лично использую

[[  ${#args} -lt 5 && "${args//[[:space:]]/}" == "-i" ]] && args="-Hin"
args="${args:--Hns} --color=auto"

Смежная тема: как всегда использовать rgrep с цветом

mnono
источник
rgrep предоставляется пакетом grep, который по умолчанию устанавливается в Ubuntu.
Карел
2

Обновление 2:

Эта строка команд использует findи grepустраняет проблему:

$ find path_to_search_in -type f -exec grep -in searchString {} 2> /dev/null +

--color=<always or auto> для цветного вывода:

$ find path_to_search_in -type f \
            -exec grep --color=always -in searchString {} 2>/dev/null +

Пример:

$ find /tmp/test/ -type f -exec grep --color=auto -in "Search string" {} 2>/dev/null +

Пример запуска в снимке ниже: SNAP1


Обновление 1:

Вы можете попробовать следующий код; как функция в вашем .bashrcили .bash_aliasesили в скрипте:

wherein () 
{ 
    for i in $(find "$1" -type f 2> /dev/null);
    do
        if grep --color=auto -i "$2" "$i" 2> /dev/null; then
            echo -e "\033[0;32mFound in: $i \033[0m\n";
        fi;
    done
}

Использование: wherein /path/to/search/in/ searchkeyword

пример:

$ wherein ~/Documents/ "hello world"

(Примечание: как предложено в комментариях ниже @enzotib, это не работает с файлами / каталогами, включая пробелы в их именах.)


Оригинальный пост

Для поиска строки и вывода только этой строки вместе со строкой поиска:

$ for i in $(find /path/of/target/directory -type f); do \
    grep -i "the string to look for" "$i"; done

например:

$ for i in $(find /usr/share/applications -type f); \
    do grep -i "web browser" "$i"; done

Чтобы отобразить имя файла, содержащее строку поиска:

$ for i in $(find /path/of/target/directory -type f); do \
    if grep -i "the string to look for" "$i" > /dev/null; then echo "$i"; fi; done;

например:

$ for i in $(find /usr/share/applications -type f); \
    do if grep -i "web browser" "$i" > /dev/null; then echo "$i"; \
    fi; done;
точный
источник
Сбой на именах файлов, содержащих пробелы. Отказ скрывается тем, что stderr не отображается.
энзотиб
@enzotib спасибо за указание на это ... это все еще не решено для указанной функции .. Я добавил еще один однострочный текст ..
точный
Теперь ответ похож на @dmityugov.
энзотиб
да, но в этом смысле большинство ответов на этой странице, если вы проверите, похожи в том, что они используют grep, за исключением того, что это подмножество, использующее findс grep..., но если вы хотите принять различные переключатели и настройки в качестве отдельного ответа, наверно мое тоже подойдет сюда .. или ты отличаешься? последнее обновление делает то, что я хотел бы в моем поиске: имена файлов со строками с ключом поиска и строкой №. тоже :) и цветной вывод и фильтр ошибок для лучшей читабельности ..
точный
2

grep( GNU или BSD )

Вы можете использовать grepинструмент для рекурсивного поиска текущей папки с -rпараметром, например:

grep -r "pattern" .

Примечание: -r- Рекурсивно ищите подкаталоги.

Для поиска в определенных файлах вы можете использовать синтаксис типа:

grep "class foo" **/*.c

Примечание. Используя параметр globbing ( **), он рекурсивно сканирует все файлы с определенным расширением или шаблоном. Чтобы включить этот синтаксис, выполните следующую команду: shopt -s globstar. Вы также можете использовать **/*.*для всех файлов (за исключением скрытых и без расширения) или любой другой шаблон.

Если вы ошиблись в том, что ваш аргумент слишком длинный, попробуйте сузить область поиска или используйте findвместо этого такой синтаксис, как:

find . -name "*.php" -execdir grep -nH --color=auto foo {} ';'

Альтернативно использовать ripgrep.

ripgrep

Если вы работаете над большими проектами или большими файлами, вы должны использовать ripgrepвместо этого, например:

rg "pattern" .

Ознакомьтесь с документами, инструкциями по установке или исходным кодом на странице проекта GitHub .

Это гораздо быстрее , чем любой другой инструмент , как GNU / BSD grep , ucg, ag, sift, ack, ptили подобного, так как он построен на вершине регулярных выражений Руста , который использует конечные автоматы, SIMD и агрессивные буквенные оптимизации , чтобы сделать поиск очень быстро.

Он поддерживает шаблоны игнорирования, указанные в .gitignoreфайлах, поэтому один путь к файлу можно сопоставить с несколькими шаблонами глобуса одновременно.


Вы можете использовать общие параметры, такие как:

  • -i - Нечувствительный поиск.
  • -I - игнорировать двоичные файлы.
  • -w - Поиск целых слов (в отличие от частичного совпадения слов).
  • -n - Показать линию вашего матча.
  • -C/ --context(например -C5) - Увеличивает контекст, поэтому вы видите окружающий код.
  • --color=auto - Отметьте соответствующий текст.
  • -H - Отображает имя файла, где находится текст.
  • -c- Отображает количество совпадающих линий. Может сочетаться с -H.
kenorb
источник
1

Я делаю это с помощью xargs, очень недооцененной команды

find ./ -type f -print0 | xargs -0 grep 'string_you_are_looking_for'

find ./ дает вам рекурсивный список всех файлов в текущей папке, а затем вы передаете его xargs, который выполняет команду grep для каждого из этих файлов.

deadprogrammer
источник
4
Использование xargsбез -print0параметров to findи -0option xargsустарело, оно не будет работать с именами файлов, содержащими пробелы.
энзотиб
@enzotib Я отредактировал ответ, как вы предложили. Пожалуйста, просмотрите и, если вам нужно отредактировать и исправить, я с радостью отредактирую вас. спасибо
αғsнιη
1
@KasiyA: теперь все в порядке, убрал мое понижение.
энзотиб
0

Я знаю, что здесь есть много ответов, но вот альтернатива, если вы хотите добавить другие ограничения при поиске файлов:

find . -type f -exec grep --quiet string_to_look_for {} ';' -print

Это работает, потому grepчто вернет 0, если он нашел результат, 1 в противном случае. Например, вы можете найти файлы размером 1 МБ и содержащие что-то:

find . -type f -exec grep --quiet string_to_look_for {} ';' -size 1M -print

Для множества требований вы, вероятно, захотите использовать флаг оптимизатора -O, существующий в GNU grep.

Ztyx
источник
0

Скрипт (find-in-code) для поиска в C, код CPP:

#!/bin/sh

find . \( -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" \) -type f -print0 | xargs -0 grep --color -n "$1"

Использование:

find-in-code "search string"
ПНВ
источник