Як використовувати команду grep для пошуку тексту, включаючи підкаталоги


373

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


grep -RIn <yor pattern> * Шукатиме з поточних каталогів у всіх текстових файлах. Не впевнений, як робити пошук рекурсивно у шаблонах файлів на зразок * .C з лише grep

1
--include="*.C"Підстановка з опцією, @ user311346, завдяки @Lekensteyn.
Боб Штейн

Використовуйте комбінацію знаходження та grep для рекурсивного пошуку файлів для рядка в поточному та всіх підкаталогах. Перевірте це wilddiary.com/find-files-contain-my-text
Дрона

Відповіді:


487

Було б краще використовувати

grep -rl "string" /path

де

  • -r(або --recursive) варіант використовується для проходження також усіх підкаталогів /path, тоді як
  • -l(або --files-with-matches) опція використовується для друку grepфайлових файлів відповідних файлів, а не відповідних рядків (це також може підвищити швидкість, враховуючи, що при першому збігу з цією опцією зупиняється читання файлу).

13
Насправді, якщо "рядок" є текстовим шаблоном для пошуку, краще використовувати цю функціональність, інакше хтось може зіткнутися з проблемами, коли рядок містить крапку або спеціальний символ, який має значення в регулярних виразах, а не просто крапку, яку слід знайти як рядок , як є. Тоді я б використовував -rlFперемикачі, -Fдля "фіксованої рядки" (а не regexp - наприклад). Звичайно, якщо в завданні було використання регулярних виразів, то вибачте мене. Зрозуміло, та сама теорія без -r теж я часто бачу, що люди припускають, що пошук "grep" шукає "текст", і це може спричинити проблеми, які спеціальні, що означають щось, як regexp.
ЛГБ

4
Є також -iпрапор, який ігнорує випадок.
Марко Цеппі

3
Я хотів би лише показати --recursiveваріант, є безліч варіантів та сценарії використання, про які можна говорити. Я почав з @dmityugov прийняв відповідь і змінив роботу без find.
enzotib

1
@NN: done :-)
enzotib

3
@ScottBiggs: з вибором--include '*.h'
enzotib

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.

Приклад виведення


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.
enzotib

Я цього не знав, це завжди працювало так, як я очікував. Це моя команда за замовчуванням при пошуку файлів.
Лекенштейн

1
Чи є спосіб розглянути лише файли із, скажімо, .a-розширенням (і поєднати це з -r)?
user2413

6
@ user2413 Спробуйте--include '*.*'
Lekensteyn

1
@alper Trygrep --exclude='*~' ...
Lekensteyn

24

Я вважаю, ви можете використовувати щось подібне:

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

Пояснення з коментарів

findце команда, яка дозволяє знаходити файли та інші об'єкти, такі як каталоги та посилання у підкаталогах заданого шляху. Якщо ви не вказали маску, якій повинні відповідати імена файлів, вона перераховує всі об'єкти каталогів.

  • -type f вказує, що він повинен обробляти лише файли, а не каталоги тощо.
  • -exec grepвизначає, що для кожного знайденого файла він повинен запустити команду grep, передаючи своє ім'я файлу як аргумент, замінивши {}ім'я файлу

3
Просто для тих, хто не знає, додавання -name '*.py'обмежує відповідність файлам, що закінчуються на ".py".
Даніель Ф

Мені подобається, що це стосується клієнтів, у яких команда grep не реалізована -R.
Aviose

Якщо ви хочете надрукувати відповідний рядок І ім'я файлу, зробіть виконання таким чином:... -exec bash -c 'grep -r "mystring" {} && echo {}' \;
Донн Лі

Який відносний перф для простого використання грепу?
Джонатан

19

Моя команда за замовчуванням -

grep -Rin string *

Я використовую капітолій 'R', оскільки lsвикористовує його для рекурсивної. Оскільки grep приймає обоє, немає причин не використовувати його.

EDIT: за HVNSweeting, мабуть, -Rбуде слідувати посиланнями, де як -rне буде.


1
Для пошуку в прихованих файлах також запустіть shopt -s dotglob(запам’ятайте -sяк «встановити»). Тоді будьте обережні, видаляючи файли. Якщо ви ввімкнули dotglob, вилучаєте rm -r *все в поточному режимі, але також і каталог над ним, оскільки ..відповідає. Щоб відключити dotglob, використовуйте shopt -u dotglob("unset"). Однак зміни є тимчасовими, вони стосуються лише поточної оболонки.
Лекенштейн

Я забув про це. Чи є спосіб встановити його для однієї лінії? щось на кшталт shopt -s dotglob & <grep cmd> & shopt -y dotglobтільки зручнішого? Таким чином нам не доведеться турбуватися про її скидання
user606723

Крім того, це, мабуть, простіше використовувати grep -Rin string .у більшості цих випадків. Я просто використовую *, тому що це, здається, виходить більш природно.
user606723

1
якщо ви робите рекурсивний греп, то можете просто почати з "". замість "*". не потрібен дотглоб.
Michał Šrajer

1
проголосуйте за це, одне, що не згадується на сторінці, - Rце переходити до символічних посилань, rне так
HVNSсолодкий

12

Якщо ви готові спробувати щось нове, ackпостріліть. Команда для рекурсивного пошуку в поточному каталозі string:

ack string

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

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

(За умови, що ви вже отримали довідник ~/binі бажано, щоб він був у вас PATH.)


2
Або просто apt-get install ack-grep (і додайте у свій .bashrc псевдонім ack = ack-grep)
markijbema

Що роблять останні параметри chmodкоманди? Вони специфічні для них chmodчи вони пов'язані з басом ( !#:3частина)?
Елліотт Дарфінк

@ElliottDarfink Використовуючи функцію історії Баша, - !це позначальник подій . Вони досить потужні, щоб уникнути повторів. !#:3посилається на третій маркер командного рядка поки що, тобто ~/bin/ackв цьому випадку.
Конрад Рудольф

4

Команда rgrep призначена для такої потреби

Якщо немає, ви можете отримати його так

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

Ви можете безпосередньо встановити настройки за замовчуванням за замовчуванням, як описано вище.

Я особисто використовую

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

пов'язана тема: як завжди використовувати rgrep з кольором


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 +

Приклад запуску на знімку нижче: оснащення1


Оновлення 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

@enzotib спасибі за те, що вказали, що це все ще не вирішено для вказаної функції .. Хоча я додав ще один вкладиш
точно

Тепер відповідь схожа на відповідь @dmityugov.
enzotib

да, але в цьому сенсі більшість відповідей на цій сторінці , якщо ви перевіряєте схожі щодо , що вони використовують 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.

1

Я роблю це за допомогою xargs, дуже недооціненої команди

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

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


4
Використовуючи xargsбез -print0опції до findта -0опцію для xargsзастарілого, вона не матиме назв файлів, що містять пробіли.
enzotib

@enzotib Я відредагував відповідь так, як ви запропонували. - Будь ласка, перегляньте, і якщо вам потрібно буде редагувати та виправляти, я буду радий повторним редагуванням вами. дякую
αғsnιη

1
@KasiyA: це нормально зараз, видалили свій нижчий запис.
enzotib

0

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

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

Це працює, тому що grepповерне 0, якщо знайде результат, 1 в іншому випадку. Наприклад , ви можете знайти файли 1 MB великий і містить дещо - що:

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

Для кількох вимог, ймовірно, ви хочете використовувати прапор оптимізатора, -Oякий існує в GNU grep.


0

Сценарій (код пошуку) для пошуку в 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"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.