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

Двоичные файлы grepping и UTF16

Стандарт grep/pcregrep и т.д. удобно использовать с двоичными файлами для данных ASCII или UTF8 - есть ли простой способ заставить их попробовать UTF16 тоже (желательно одновременно, но вместо этого будет делать)?

Данные, которые я пытаюсь получить, это все ASCII в любом случае (ссылки в библиотеках и т.д.), он просто не найден, как иногда там 00 между любыми двумя символами, а иногда и нет.

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

4b9b3361

Ответ 1

Самый простой способ - просто преобразовать текстовый файл в utf-8 и передать его в grep:

iconv -f utf-16 -t utf-8 file.txt | grep query

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

Кажется, что grep преобразует запрос utf-16 в utf-8/ascii. Вот что я пробовал:

grep `echo -n query | iconv -f utf-8 -t utf-16 | sed 's/..//'` test.txt

Если test.txt - это файл utf-16, это не сработает, но оно работает, если test.txt - ascii. Я могу только сделать вывод, что grep преобразует мой запрос в ascii.

EDIT: Здесь действительно действительно сумасшедший, который работает, но не дает вам очень полезной информации:

hexdump -e '/1 "%02x"' test.txt | grep -P `echo -n Test | iconv -f utf-8 -t utf-16 | sed 's/..//' | hexdump -e '/1 "%02x"'`

Как это работает? Он преобразует ваш файл в шестнадцатеричный (без дополнительного форматирования, который обычно применяется в hexdump). Он соединяет это с grep. Grep использует запрос, который создается путем повторения вашего запроса (без новой строки) в iconv, который преобразует его в utf-16. Затем он передается в sed для удаления спецификации (первые два байта файла utf-16, используемые для определения сущности). Затем он передается в hexdump так, чтобы запрос и вход совпадали.

К сожалению, я думаю, что это приведет к распечатке файла ENTIRE, если есть одно совпадение. Кроме того, это не будет работать, если utf-16 в вашем двоичном файле будет храниться в другой форме, чем ваша машина.

EDIT2: Получил это!!!!

grep -P `echo -n "Test" | iconv -f utf-8 -t utf-16 | sed 's/..//' | hexdump -e '/1 "x%02x"' | sed 's/x/\\\\x/g'` test.txt

Здесь выполняется поиск шестнадцатеричной версии строки Test (в utf-16) в файле test.txt

Ответ 2

Вы можете явно указать нули (00s) в строке поиска, хотя вы получите результаты с нулями, поэтому вы можете перенаправить вывод в файл, чтобы вы могли просмотреть его с помощью разумного редактора или передать его через sed, чтобы заменить нули. Поиск "bar" в *.utf16.txt:

grep -Pa "b\x00a\x00r" *.utf16.txt | sed 's/\x00//g'

"-P" сообщает grep принять синтаксис regexp Perl, который позволяет \x00 расширяться до нуля, а -a говорит ему игнорировать тот факт, что Unicode выглядит как двоичный.

Ответ 3

Я обнаружил, что приведенное ниже решение лучше всего работает для меня, с https://www.splitbits.com/2015/11/11/tip-grep-and-unicode/

Grep не очень хорошо работает с Unicode, но его можно обойти. Например, чтобы найти,

Some Search Term

в файле UTF-16 используйте регулярное выражение, чтобы игнорировать первый байт в каждом символе,

S.o.m.e. .S.e.a.r.c.h. .T.e.r.m 

Также, скажите grep, чтобы он обрабатывал файл как текст, используя '-a', последняя команда выглядит следующим образом:

grep -a 'S.o.m.e. .S.e.a.r.c.h. .T.e.r.m' utf-16-file.txt

Ответ 4

Я использую это все время после сброса реестра Windows, поскольку его вывод является unicode. Это работает под Cygwin.

$ regedit /e registry.data.out
$ file registry.data.out
registry.data.out: Little-endian **UTF-16 Unicode text**, with CRLF line terminators

$ sed 's/\x00//g' registry.data.out | egrep "192\.168"
"Port"="192.168.1.5"
"IPSubnetAddress"="192.168.189.0"
"IPSubnetAddress"="192.168.102.0"
[HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Print\Monitors\Standard TCP/IP Port\Ports\192.168.1.5]
"HostName"="192.168.1.5"
"Port"="192.168.1.5"
"LocationInformation"="http://192.168.1.28:1215/"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"StandaloneDhcpAddress"="192.168.173.1"
"ScopeAddressBackup"="192.168.137.1"
"ScopeAddress"="192.168.137.1"
"DhcpIPAddress"="192.168.1.24"
"DhcpServer"="192.168.1.1"
"0.0.0.0,0.0.0.0,192.168.1.1,-1"=""
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Print\Monitors\Standard TCP/IP Port\Ports\192.168.1.5]
"HostName"="192.168.1.5"
"Port"="192.168.1.5"
"LocationInformation"="http://192.168.1.28:1215/"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"LocationInformation"="http://192.168.1.5:80/WebServices/Device"
"StandaloneDhcpAddress"="192.168.173.1"
"ScopeAddressBackup"="192.168.137.1"
"ScopeAddress"="192.168.137.1"
"DhcpIPAddress"="192.168.1.24"
"DhcpServer"="192.168.1.1"
"0.0.0.0,0.0.0.0,192.168.1.1,-1"=""
"MRU0"="192.168.16.93"
[HKEY_USERS\S-1-5-21-2054485685-3446499333-1556621121-1001\Software\Microsoft\Terminal Server Client\Servers\192.168.16.93]
"A"="192.168.1.23"
"B"="192.168.1.28"
"C"="192.168.1.200:5800"
"192.168.254.190::5901/extra"=hex:02,00
"00"="192.168.254.190:5901"
"ImagePrinterPort"="192.168.1.5"

Ответ 5

Мне нужно было сделать это рекурсивно, и вот что я придумал:

find -type f | while read l; do iconv -s -f utf-16le -t utf-8 "$l" | nl -s "$l: " | cut -c7- | grep 'somestring'; done

Это абсолютно ужасно и очень медленно; Я уверен, что там лучший способ, и я надеюсь, что кто-то может улучшить его, но я спешил: P

Что делают штуки:

find -type f

дает рекурсивный список имен файлов с путями относительно текущего

while read l; do ... done

Bash цикл; для каждой строки списка путей файла, поместите путь в $l и выполните предмет в цикле. (Почему я использовал цикл оболочки вместо xargs, что было бы намного быстрее: мне нужно префикс каждой строки вывода с именем текущего файла. Не мог бы подумать о том, как это сделать, если бы я кормил несколько файлов сразу в iconv, и так как я собираюсь делать один файл за раз в любом случае, цикл оболочки проще синтаксис/экранирование.)

iconv -s -f utf-16le -t utf-8 "$l"

Преобразуйте файл с именем в $l: предположим, что входной файл является utf-16 little-endian и преобразует его в utf-8. -s заставляет iconv останавливаться на любых ошибках преобразования (их будет много, потому что некоторые файлы в этой структуре каталогов не являются utf-16). Результат этого преобразования переходит в стандартный вывод.

nl -s "$l: " | cut -c7-

Это взломать: nl вставляет номера строк, но имеет место "использовать эту произвольную строку для разделения номера из строки", поэтому я помещаю имя файла (за которым следует двоеточие и пробел) в этом, Затем я использую cut, чтобы удалить номер строки, оставив только префикс имени файла. (Почему я не использовал sed: escaping намного проще. Если я использовал выражение sed, мне приходится беспокоиться о наличии символов регулярных выражений в именах файлов, что в моем случае было много. nl намного глубже, чем sed, и просто возьмет параметр -s в буквальном смысле, а оболочка обработает экранирование для меня.)

Итак, к концу этого конвейера я конвертировал кучу файлов в строки utf-8 с префиксом имени файла, который я тогда grep. Если есть совпадения, я могу указать, в каком файле они находятся из префикса.

Предостережения

  • Это намного медленнее, чем grep -R, потому что я создаю новую копию iconv, nl, cut и grep для каждого отдельного файла. Это ужасно.
  • Все, что не является входом utf-16le, выйдет как полный мусор, поэтому если есть обычный файл ASCII, содержащий "somestring", эта команда не сообщит об этом - вам нужно сделать обычный grep -R а также эту команду (и если у вас несколько типов кодировки Unicode, например, некоторые файлы большого и младшего порядка, вам нужно настроить эту команду и запустить ее снова для каждой различной кодировки).
  • Файлы, имя которых содержит "somestring", будут отображаться на выходе, даже если их содержимое не имеет совпадений.

Ответ 6

ripgrep

Используйте утилиту ripgrep для grep файлов UTF-16.

ripgrep поддерживает поиск файлов в текстовых кодировках, отличных от UTF-8, таких как UTF-16, latin-1, GBK, EUC-JP, Shift_JIS и других. (-E некоторая поддержка автоматического определения UTF-16. Другие кодировки текста должны быть специально указаны с помощью -E/--Encoding flag.)

Пример синтаксиса:

rg sometext file

Чтобы сбросить все строки, выполните: rg -N. file rg -N. file

Ответ 7

Утверждение sed больше, чем я могу обернуть вокруг себя. У меня есть упрощенный, далеко не идеальный TCL script, который, я думаю, выполняет работу OK с моей тестовой точкой:

#!/usr/bin/tclsh

set insearch [lindex $argv 0]

set search ""

for {set i 0} {$i<[string length $insearch]-1} {incr i} {
    set search "${search}[string range $insearch $i $i]."
}
set search "${search}[string range $insearch $i $i]"

for {set i 1} {$i<$argc} {incr i} {
    set file [lindex $argv $i]
    set status 0
    if {! [catch {exec grep -a $search $file} results options]} {
        puts "$file: $results"
    }
}

Ответ 8

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

// Define grepreg in bash by pasting at bash command prompt
grepreg ()
{
    find -name '*.reg' -exec echo {} \; -exec iconv -f utf-16 -t utf-8 {} \; | grep "$1\|\.reg"
}

// Sample usage
grepreg SampleTextToSearch

Ответ 9

Вы можете использовать следующие Ruby однострочные:

ruby -e "puts File.open('file.txt', mode:'rb:BOM|UTF-16LE').readlines.grep(Regexp.new 'PATTERN'.encode(Encoding::UTF_16LE))"

Для простоты это можно определить как функцию оболочки, например:

grep-utf16() { ruby -e "puts File.open('$2', mode:'rb:BOM|UTF-16LE').readlines.grep(Regexp.new '$1'.encode(Encoding::UTF_16LE))"; }

Затем он будет использован аналогично grep:

grep-utf16 PATTERN file.txt

Источник: Как использовать Ruby's readlines.grep для файлов UTF-16?

Ответ 10

ugrep (Universal grep) поддерживает Unicode, файлы UTF-8/16/32, обнаруживает недопустимый Unicode для обеспечения правильных результатов, отображает текстовые и двоичные файлы, а также работает быстро и бесплатно:

ugrep ищет входные UTF-8/16/32 и другие форматы. Опция --encoding позволяет выполнять поиск во многих других форматах файлов, таких как ISO-8859-1, EBCDIC и кодовых страницах 437, 850, 858, 1250–1258.

Скачать угреп с GitHub