Подтвердить что ты не робот

Grep но индексируемый?

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

Есть ли утилита командной строки, подобная grep, которая обладает способностью индексирования?

4b9b3361

Ответ 1

Решения ниже довольно просты. Есть много угловых случаев, которые они не охватывают:

  • поиск начала строки ^
  • имена файлов, содержащие \n или: потерпят неудачу
  • имена файлов, содержащие пробелы, потерпят неудачу (хотя это можно исправить с помощью GNU Parallel вместо xargs)
  • поиск строки, соответствующей пути к другим файлам, будет неоптимальным

Преимущество решений в том, что они очень просты в реализации.

Решение 1: один большой файл

Факт: поиск очень медленный, чтение одного большого файла часто быстрее.

Учитывая эти факты, идея состоит в том, чтобы просто создать индекс, содержащий все файлы со всем их содержимым - каждая строка должна начинаться с имени файла и номера строки:

Индекс DIR:

find . -type f -print0 | xargs -0 grep -Han . > .index

Используйте индекс:

grep foo .index

Решение 2: один большой сжатый файл

Факт: жесткие диски медленные. Ищу очень медленно. Многоядерные процессоры нормальные.

Так что может быть быстрее прочитать сжатый файл и распаковать его на лету, чем читать несжатый файл - особенно если у вас достаточно оперативной памяти для кэширования сжатого файла, но недостаточно для несжатого файла.

Индекс DIR:

find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index

Используйте индекс:

pbzcat .index | grep foo

Решение 3: использовать индекс для поиска потенциальных кандидатов

Создание индекса может занять много времени, и вы можете не захотеть делать это для каждого отдельного изменения в каталоге.

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

sort -u необходима, чтобы избежать многократного поиска одного и того же файла.

Индекс DIR:

find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index

Используйте индекс:

pbzcat .index | grep foo | sed s/:.*// | sort -u | xargs grep foo

Решение 4: добавить в указатель

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

Индекс DIR:

find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index

Добавить в указатель:

find . -type f -newer .index -print0 | xargs -0 grep -Han . | pbzip2 >> .index

Используйте индекс:

pbzcat .index | grep foo | sed s/:.*// | sort -u | xargs grep foo

Это может быть даже быстрее, если вы используете pzstd вместо pbzip2/pbzcat.

Решение 5: используйте git

git grep может выполнять поиск через git-репозиторий. Но он, похоже, выполняет много операций поиска и в 4 раза медленнее в моей системе, чем решение 4.

Хорошей частью является то, что индекс .git меньше, чем .index.bz2.

Индекс DIR:

git init
git add .

Добавить в указатель:

git add .

Используйте индекс:

git grep foo

Решение 6: оптимизировать git

Git помещает свои данные во множество маленьких файлов. Это приводит к поиску. Но вы можете попросить git сжать маленькие файлы в несколько больших:

git gc --aggressive

Это занимает некоторое время, но очень эффективно упаковывает индекс в несколько файлов.

Теперь вы можете сделать:

find .git  -type f | xargs cat >/dev/null
git grep foo

git будет много искать в индексе, но сначала запустив cat, вы поместите весь индекс в RAM.

Добавление к индексу аналогично решению 5, но время от времени запускайте git gc чтобы избежать большого количества маленьких файлов, и git gc --aggressive чтобы сэкономить больше места на диске, когда система простаивает.

git не освободит место на диске, если вы удалите файлы. Поэтому, если вы удаляете большие объемы данных, удалите .git и выполните git init; git add. git init; git add. снова.

Ответ 2

Существует проект https://code.google.com/p/codesearch/, который способен создавать индекс и быстрый поиск в индексе. Регулярные выражения поддерживаются и вычисляются с использованием индекса (фактически, только подмножество regexp может использовать индекс для фильтрации набора файлов, а затем реальное регулярное выражение повторно проверяется на сопоставленные файлы).

Индекс от кодового поиска обычно составляет 10-20% от размера исходного кода, построение индекса происходит быстро, как запуск классического grep 2 или 3 раза, а поиск почти мгновен.

Идеи, используемые в проекте кодового поиска, находятся на сайте поиска кода Google (RIP). Например. индекс содержит карту из n-граммов (3-граммов или каждый 3-байтовый набор, найденный в ваших источниках) в файлы; и regexp переводится на 4 грамма при поиске.

PS И есть ctags и cscope для навигации по источникам C/С++. Ctags может найти декларации/определения, cscope более способна, но имеет проблемы с С++.

PPS, а также есть инструменты для языка C/С++/ObjC: http://blog.wuwon.id.au/2011/10/vim-plugin-for-navigating-c-with.html и clang-complete

Ответ 3

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

Не обращаясь к части способности к индексированию, git grep будет иметь с git 2.8 (Q1 2016) возможность выполнения параллелизма!

См. commit 89f09dd, commit 044b1f3, commit b6b468b (15 декабря 2015 г.) Виктор Лещук (vleschuk).
(объединено Junio ​​C Hamano - gitster - в commit bdd1cc2, 12 января 2016 г.

grep: добавить --threads=<num> и grep.threads конфигурацию

"git grep" теперь можно настроить (или указать из командной строки), как много потоков, которые нужно использовать при поиске в рабочих файлах дерева.

grep.threads:

Число рабочих потоков grep для использования.

Ответ 4

ack - инструмент поиска кода, оптимизированный для программистов, особенно программистов, работающих с большими разнородными исходными кодами: http://beyondgrep.com/

Являются ли некоторые из ваших примеров поиска, где вы хотите только искать определенный тип файла, например, только файлы Java? Затем вы можете сделать

ack --java function

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

И если ack не делает этого для вас, вот список многих инструментов, предназначенных для поиска исходного кода: http://beyondgrep.com/more-tools/

Ответ 5

В этой статье grep-cache есть script для кеширования результатов grep. Его примеры выполнялись на окнах с установленными инструментами linux, поэтому их можно было легко использовать на nix/mac с небольшими изменениями. Это в основном просто perl script.

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

Кэш обычно находится в /proc/sys/vm/drop_caches, если вы хотите вручную стереть его, чтобы увидеть увеличение скорости от неэкранированного до кэшированного grep.

Ответ 6

Поскольку вы упоминаете различные типы текстовых файлов, которые на самом деле не являются кодом, я предлагаю вам взглянуть на GNU ID utils. Например:

cd /tmp
# create index file named 'ID'
mkid -m /dev/null  -d text /var/log/messages.*
# query index
gid -r 'spamd|kernel'

Эти инструменты фокусируются на токенах, поэтому запросы на строки токенов невозможны. Минимальная интеграция в emacs для команды gid.

Для более конкретного случая индексации исходного кода я предпочитаю использовать GNU global, который я считаю более гибким. Например:

cd sourcedir
# index source tree
gtags .
# look for a definition
global -x main
# look for a reference
global -xr printf
# look for another kind of symbol
global -xs argc

Глобально поддерживает C/С++ и Java и с небольшим количеством настроек может быть расширена для поддержки многих других языков. Он также имеет очень хорошую интеграцию с emacs: последовательные запросы сложены, а обновление исходного файла эффективно обновляет индекс. Однако я не знаю, что он может индексировать простой текст (пока).

Ответ 7

Мы используем инструмент для внутренней индексации очень больших файлов журналов и производим их эффективный поиск. Это было с открытым исходным кодом. Я не знаю, насколько хорошо он масштабируется до большого количества файлов. По умолчанию он многопоточен, он ищет внутри сжатых файлов и кэширует индексы ранее найденных файлов.

https://github.com/purestorage/4grep