Что заставляет grep полагать, что файл является двоичным?

Существует хороший инструмент для установки Ваших цветов для команды ls - http://geoff.greer.fm/lscolors/

197
09.02.2015, 13:02
10 ответов

Если существует a NUL изобразите где угодно в файле, grep рассмотрит это как двоичный файл.

Там мог бы обходное решение как это cat file | tr -d '\000' | yourgrep устранить весь пустой указатель сначала и затем перерыть файл.

133
27.01.2020, 19:27
  • 1
    ... или использование -a/--text, по крайней мере, с GNU grep. –  derobert 26.11.2012, 22:44
  • 2
    @derobert: на самом деле, в некоторых (более старых) системах, grep видят строки, но его вывод усечет каждый согласующий отрезок длинной линии в первом NUL (вероятно, becauses это называет C printf и дает ему подобранную строку?). В такой системе a grep cmd .sh_history возвратит столько же пустых строк, сколько существуют строки, соответствующие 'cmd', поскольку каждая строка sh_history имеет определенный формат с a NUL в начале каждой строки. (но Ваш комментарий, "по крайней мере, о GNU grep", вероятно, осуществляется. У меня нет того под рукой прямо сейчас для тестирования, но я ожидаю, что они обрабатывают это приятно), –  Olivier Dulac 25.11.2013, 13:46
  • 3
    Является присутствие символа NUL единственными критериями?Вряд ли. Это, вероятно, более умно, чем это. Что-либо выходящее за пределы ASCII диапазон, 32-126 был бы моим предположением, но мы должны будем посмотреть на исходный код, чтобы быть уверенными. –  Michael Martinez 14.08.2015, 19:58
  • 4
    Моя информация была из страницы справочника определенного grep экземпляра. Ваш комментарий о реализации действителен, источник превосходит документы. –  bbaja42 19.08.2015, 01:31
  • 5
    у меня был файл который grep на рассмотренном двоичном файле cygwin, потому что это имело длинного тире (0x96) вместо регулярного дефиса/минус ASCII (0x2d). Я предполагаю, что этот ответ решил вопрос OP, но кажется, что это неполно. –  cp.engr 15.02.2016, 18:15

Файл /etc/magic или /usr/share/misc/magic имеет список последовательностей что команда file использование для определения типа файла.

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

grep на Linux имеет некоторые опции обработать двоичные файлы как --binary-files или -U / --binary

5
27.01.2020, 19:27

Можно использовать strings утилита, чтобы извлечь текстовое содержание из любого файла и затем передать его по каналу через grep, как это: strings file | grep pattern.

21
27.01.2020, 19:27
  • 1
    Идеал для захвата файлов журнала, которые могли бы быть частично повреждены –  Hannes R. 27.02.2015, 09:43
  • 2
    да, иногда двоичный файл смешивался, вход также происходит. Это хорошо. –  sdkks 03.09.2017, 19:59

Один из моих текстовых файлов был внезапно рассматривается как двоичный GREP:

$ file foo.txt
foo.txt: ISO-8859 text

решение было Чтобы преобразовать его с помощью ICONV :

iconv -t UTF-8 -f ISO-8859-1 foo.txt > foo_new.txt
6
27.01.2020, 19:27

У меня была такая же проблема. Я использовал VI -B [Имя файла] , чтобы увидеть добавленные символы. Я нашел контрольные символы ^ @ и ^ м . Тогда в VI тип : 1, $ S / ^ @ // G для удаления символов ^ @ . Повторите эту команду для ^ м .

ПРЕДУПРЕЖДЕНИЕ. Чтобы получить «синие» управляющие символы, нажмите CTRL + V затем Ctrl + M или Ctrl + @ . Тогда сохраните и выйдите из VI.

1
27.01.2020, 19:27

На вопрос "Что заставляет grep считать файл двоичным? ", вы можете использовать iconv:

$ iconv < myfile.java
iconv: (stdin):267:70: cannot convert

В моем случае были испанские символы, которые правильно отображались в текстовых редакторах, но grep считал их двоичными; iconv вывод указывал мне на номера строк и столбцов этих символов

В случае NUL символов, iconv будет считать их нормальными и не будет печатать такой вывод, поэтому данный метод не подходит

.
2
27.01.2020, 19:27

Один из моих учеников была эта проблема. Ошибка в grep в Cygwin . Если файл содержит символы, отличные от Ascii, grep и egrep воспринимают его как двоичный.

2
27.01.2020, 19:27

grep -a работал у меня:

$ grep --help
[...]
 -a, --text                equivalent to --binary-files=text
133
27.01.2020, 19:27

GNU grep 2.24 RTFS

Вывод: только 2 и 2 случая:

  • NUL, например printf 'a\0' | grep 'a'

  • ошибка кодировки согласно C99 mbrlen(), например:

    export LC_CTYPE='en_US.UTF-8'
    printf 'a\x80' | grep 'a'
    

    потому что \x80 не может быть первым байтом точки Юникода UTF-8: UTF-8 - Описание | en.wikipedia.org

Кроме того, как упоминал Стефан Шазелас Что заставляет grep считать файл бинарным? | Unix & Linux Stack Exchange, эти проверки выполняются только до первого чтения буфера длиной TODO.

Только до первого чтения буфера

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

Я полагаю, что это сделано из соображений производительности.

Например: это печатает строку:

printf '%10000000s\n\x80a' | grep 'a'

а это нет:

printf '%10s\n\x80a' | grep 'a'

Фактический размер буфера зависит от того, как читается файл. Например, сравните:

export LC_CTYPE='en_US.UTF-8'
(printf '\n\x80a') | grep 'a'
(printf '\n'; sleep 1; printf '\x80a') | grep 'a'

При sleep первая строка передается в grep, даже если ее длина всего 1 байт, потому что процесс уходит в сон, а при втором чтении не проверяется, является ли файл бинарным.

RTFS

git clone git://git.savannah.gnu.org/grep.git 
cd grep
git checkout v2.24

Найдите, где кодируется сообщение об ошибке stderr:

git grep 'Binary file'

Привело нас к /src/grep.c:

if (!out_quiet && (encoding_error_output
                    || (0 <= nlines_first_null && nlines_first_null < nlines)))
    {
    printf (_("Binary file %s matches\n"), filename);

Если эти переменные были хорошо названы, мы в основном пришли к выводу.

encoding_error_output

Быстрый поиск по encoding_error_output показывает, что единственный путь кода, который может его изменить, проходит через buf_has_encoding_errors:

clen = mbrlen (p, buf + size - p, &mbs);
if ((size_t) -2 <= clen)
  return true;

затем просто man mbrlen.

nlines_first_null и nlines

Инициализированы как:

intmax_t nlines_first_null = -1;
nlines = 0;

поэтому когда найден null 0 <= nlines_first_null становится true.

TODO когда nlines_first_null < nlines может быть false? Мне стало лень.

POSIX

Не определяет бинарные опции grep - поиск в файле по шаблону | pubs.opengroup.org , а GNU grep не документирует это, так что RTFS - единственный способ.

13
27.01.2020, 19:27

У меня тоже была эта проблема, но в моем случае она была вызвана слишком длинной совпадающей строкой.

file myfile.txt
myfile.txt: UTF-8 Unicode text, with very long lines

grepбудет проходить через весь файл со многими шаблонами, но когда шаблон соответствует «очень длинной строке», он останавливается на Binary file myfile.txt matches.

Добавление -aтакже решает эту проблему, но предварительный -синтаксический анализ файла на наличие NULL или других недопустимых символов не будет иметь никакого эффекта (их нет, иначе grep не завершится для других шаблонов ). В этом случае оскорбительная строка содержала более 25 тысяч символов!

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

0
02.12.2020, 15:17

Теги

Похожие вопросы