рекурсивный grep не отображает совпадения из некоторых файлов
Я использую GNU grep 3.4 для поиска скриптов, содержащих определенный шаблон. Для этого я grep
рекурсивно вызываю так
grep -rin . -e "pattern"
Шаблон - это просто слово, а не регулярное выражение. Странно то, что в выводе не перечислены вхождения в некоторых файлах, которые определенно содержат строку.
Я попытался открыть эти файлы vim
и выполнить поиск там, /pattern
и он нашел шаблон. Кодировка отображается vim
как [dos:utf-8:]
. Когда я копирую строку и записываю ее в новый файл, приведенная выше grep
команда отображает ее правильно.
Почему не grep
указан исходный файл?
Ответы
Grep (или, по крайней мере, более старые) не понимают UTF8. Таким образом, составные символы, точки переноса или другие невидимые данные могут отпугнуть grep.
Grep также зависит от значений $LC_ALL, $LC_CTYPE и $ LANG.
Используйте vim, чтобы сохранить несколько строк вокруг слова, которое grep не удалось найти, а затем сделайте шестнадцатеричный дамп этого крошечного файла примера. Вы, наверное, поймете, почему grep не удалось
Вы также можете использовать команды vim ( ga
и g8
т. Д.) Для проверки символов, но шестнадцатеричный дамп может быть более понятным
Я нашел проблему (с помощью другого ответа). Файлы 'grep' не выводили никаких результатов, потому что на самом деле они не были utf-8
закодированы, но utf-16be
. Я узнал об этом с помощью hexdump (кредиты @RedGrittyBrick):
hd file_for_which_grep_works_as_expected.txt
уступил
00000000 20 20 20 20 50 61 74 74 65 72 6e 0a | Pattern.|
0000000c
в то время как
hd file_for_which_grep_fails.txt
вернулся
00000000 fe ff 00 50 00 61 00 74 00 74 00 65 00 72 00 6e |...P.a.t.t.e.r.n|
00000010 00 0a |..|
00000012
Итак, дважды проверив кодировку с помощью
file -i file_for_which_grep_fails.txt
идентифицировал это как text/plain; charset=utf-16be
.
Я не в состоянии признать , что utf-8
показано vim
было на самом деле буфер кодирования, а не файл кодирования. Выполнение :set fileencoding
в vim
также отображается правильно fileencoding=utf-16
(здесьhttps://superuser.com/a/28783/1210682).
Итак, проблема в том, что my grep
не работает с utf-16
закодированными файлами. Это уже было описано здесь:https://superuser.com/a/231471/1210682. Тем не менее, средство преобразования utf-16
файлов , utf-8
прежде чем grep
не работает , когда я использую его рекурсивно, так как я заранее не знаю , какие файлы могут быть utf-8
и которые utf-16
и утра поиск через много файлов.
Существуют разные решения, два из которых я кратко опишу здесь:
Быстрый и грязный раствор , который работал для меня было расширить шаблон поиска , чтобы включить тот , который будет соответствовать
utf-16
версии и поиск по одной из двух моделей:grep -riPa . -e "pattern|p.a.t.t.e.r.n."
Конечно, это очень ограничено с точки зрения возможных шаблонов.
Есть альтернативы ,
grep
какugrep
илиripgrep
что (среди прочего) может обрабатыватьutf-16
файлы. В итоге я использовал тот,ripgrep
который доступен в стандартных репозиториях пакетов Ubuntu с 18.04:rg -i "pattern"
Здесь есть отличное обсуждение альтернатив: https://stackoverflow.com/questions/3752913/grepping-binary-files-and-utf16, среди них интересный подход, пытающийся преобразовать шаблон поиска utf-16
в grep
. Однако я не мог заставить его работать.