Решения, приведенные ниже, довольно просты.Есть много угловых случаев, которые они не охватывают:
- поиск начала строки ^
- имена файлов, содержащие \ n или: не удастся
- имена файлов, содержащиепробел не удастся (хотя это можно исправить с помощью GNU Parallel вместо xargs)
- поиск строки, совпадающей с путем к другим файлам, будет неоптимальным
Хорошая частьРешения заключаются в том, что они очень просты в реализации.
Решение 1: один большой файл
Факт: поиск очень медленный, чтение одного большого файла часто быстрее.
Учитывая эти факты, идея состоит в том, чтобы просто создать индекс, содержащий все файлы со всем их содержимым - каждая строка с добавлением имени файла и номера строки:
Индексировать каталог:
find . -type f -print0 | xargs -0 grep -Han . > .index
Используйте индекс:
grep foo .index
Решение 2: один большой сжатый файл
Факт: жесткие диски работают медленно.Ищу очень медленно.Многоядерные процессоры нормальны.
Так что может быть быстрее прочитать сжатый файл и распаковать его на лету, чем читать несжатый файл - особенно если у вас достаточно оперативной памяти для кэширования сжатого файла, но недостаточно длянесжатый файл.
Index a dir:
find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index
Используйте индекс:
pbzcat .index | grep foo
Решение 3: используйте индекс для поиска потенциальных кандидатов
Создание индекса может занять много времени, и вам может не потребоваться делать это для каждого отдельного изменения в каталоге.
Чтобы ускорить это, используйте индекс только для определения имен файлов, которые могут совпадать исделать реальный grep через эти (мы надеемся, ограниченное количество) файлов.Это обнаружит файлы, которые больше не совпадают, но не обнаружит новые файлы, которые соответствуют.
sort -u
необходим, чтобы избежать многократного поиска одного и того же файла.
Index a dir:
find . -type f -print0 | xargs -0 grep -Han . | pbzip2 > .index
Используйте индекс:
pbzcat .index | grep foo | sed s/:.*// | sort -u | xargs grep foo
Решение 4: добавьте к индексу
Повторное создание полного индекса может бытьочень медленно.Если большая часть директории остается прежней, вы можете просто добавить в индекс новые измененные файлы.Индекс снова будет использоваться только для поиска потенциальных кандидатов, поэтому, если файл больше не соответствует, он будет обнаружен при просмотре текущего файла.
Индекс в каталоге:
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.
Index a dir:
git init
git add .
Добавить к индексу:
git add .
Использовать индекс:
git grep foo
Решение 6: оптимизировать git
Git помещает свои данные во множество небольших файлов.Это приводит к поиску.Но вы можете попросить git сжать маленькие файлы в несколько больших файлов:
git gc --aggressive
Это занимает некоторое время, но очень эффективно упаковывает индекс в несколько файлов.
Теперь вы можетеdo:
find .git -type f | xargs cat >/dev/null
git grep foo
git
будет много искать в индексе, но, выполнив сначала cat
, вы поместите весь индекс в ОЗУ.
Добавление в индексаналогично решению 5, но время от времени запускайте git gc
, чтобы избежать большого количества маленьких файлов, и git gc --aggressive
, чтобы сэкономить больше места на диске, когда система простаивает.
git
не освобождаетместо на диске, если вы удалите файлы.Поэтому, если вы удаляете большие объемы данных, удалите .git
и снова выполните git init; git add .
.