Как я могу найти двоичные данные в моем текстовом файле?

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

Я знаю, как я могу прочитать файл в любом случае.

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

4 ответа

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

      cmp /path/to/file.log <(strings /path/to/file.log)

сравнивает файлы и сообщает вам, чем они отличаются (в отличие от diff, который сообщает вам, чем они отличаются). возвращает действительные текстовые строки из двоичных файлов.<(…)позволяет обрабатывать вывод команды как файловый дескриптор другой команды.

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

Например, я получаюA and B differ: byte 1450315, line 6390. Бегtail -n +6390 /path/to/file.log | lessпоказывает журнал, начиная с «плохой» строки, или вы можете передать его по конвейеру| hexdump -C | lessчтобы увидеть шестигранник (проходя черезhead -n 1у меня не сработало, потому что двоичный файл был\x00символы, которые отображались только при наличии пейджера)

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

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

Вначале я позвонил head -n 1, не было двоичного символа. потом head -n 2, тогда head -n 3... и так далее. Вскоре я нашел строку, где присутствовал двоичный символ.

Если у вас естьmy_fileкоторый содержит (в):

      test data 1
^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@test data 2
test data 3

grepбеспокоит нулевой байт (шестнадцатеричное значение 00, представленное как^@вvim). Если вы ищете обычную строку «данные» с помощью$ grep 'data' my_fileВы получаетеBinary file my_file matchesчто не является ожидаемым результатом. Если вы хотите проверить/удалить нулевые байты вручную, вы можете найти байты-нарушители с помощью:

      $ < my_file hexdump -C | grep -C2 ' 00'
00000000  74 65 73 74 20 64 61 74  61 20 31 0a 00 00 00 00  |test data 1.....|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 74 65  |..............te|
00000020  73 74 20 64 61 74 61 20  32 0a 74 65 73 74 20 64  |st data 2.test d|
00000030  61 74 61 20 33 0a                                 |ata 3.|

и увидите обычные строки рядом с нулевыми байтами, которые затем можно искать в vim и редактировать (не ищите точки; они представляют собой пробельные символы, такие как новая строка и нулевой байт, а не литерал..) Если вы хотите удалить их программно:

      $ < my_file sed 's/\x0//g' > my_file_without_nulls

Опираясь на замечательную идею @ibboard:find-non-printable.sh:

      #!/bin/sh
usage="$0 FILE - Locates first non-printable byte, as in 'FILE - differ: byte 21881, line 507'";
n_bytes=$(stat --printf='%s' "$1");
# -w: --include-all-whitespace
strings -w "$1" | cmp -n "$n_bytes" "$1";
  • Нет вывода, если не найдены непечатаемые символы, вместо сообщения типаcmp: EOF on FILE after byte 1677, line 47.
  • Простая труба вместо использования<(). Работает с оболочкой POSIX вместо использования Bash или ZSH. Выходные данные показывают-как имя файла вместо/dev/....
  • Работает должным образом, если файл содержит пустые строки. Для этого требуется реализация, поддерживающая-w, например GNUstrings. Без этого результат просто указывает на первую пустую строку, что часто не является желаемым результатом.
  • Пользователю необходимо ввести имя файла только один раз.
Другие вопросы по тегам