Как выполнить grep для текстового файла, содержащего некоторые двоичные данные?

123

grep возвращает

Двоичный файл test.log соответствует

Например

echo    "line1 re \x00\r\nline2\r\nline3 re\r\n" > test.log  # in zsh
echo -e "line1 re \x00\r\nline2\r\nline3 re\r\n" > test.log  # in bash
grep re test.log

Я хочу, чтобы в результате были показаны строки 1 и 3 (всего две строки).

Можно ли использовать trпреобразование непечатаемых данных в читаемые данные, чтобы grep снова работал?

Даниэль Ю.С. Лин
источник
Обратите внимание, что существует программа, которая отфильтровывает двоичные символы из двоичного файла и сохраняет только текстовые символы (читаемые). Здесь: soft.tahionic.com/download-words_extractor/index.html
InTheNameOfScience
Простите, но ... разве вы не пропали -eв echoкоманде?
Sopalajo de Arrierez
Если вы используете 'zsh', все нормально без -e. Если вы используете bash, вы должны добавить -e.
Daniel YC Lin
serverfault.com/questions/328101/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功 04

Ответы:

68

Вы можете запустить файл данных cat -v, например

$ cat -v tmp/test.log | grep re
line1 re ^@^M
line3 re^M

который затем может быть подвергнут дальнейшей постобработке для удаления мусора; это наиболее аналогично вашему запросу об использовании trдля задачи.

vielmetti
источник
5
Решил мою проблему. Спасибо! Вот что man catговорит о -v:-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
tommy.carstensen 03
Обратите внимание, что это также работает в конвейере. Egset | cat -v | grep variable
funroll
1
Зачем использовать это, если grep --text работает? Это кажется намного более сложным.
Michael Haefele 02
grep --textне всегда работает; он уважает CTRL + D как терминатор файла. Поэтому, если у вас есть это в вашем двоичном файле, grep выйдет раньше.
Томми
110
grep -a

Нет ничего проще.

Джеймс Селвакумар
источник
3
это то же самое, grep --textчто paxdiablo упомянул двумя годами ранее
user829755
4
Да, за исключением того, что это не сработает на OSX, если вы не сделаете следующее:LC_ALL="C" grep -a
Крис Стрэттон
91

Один из способов - просто обрабатывать двоичные файлы как текст, grep --textно это вполне может привести к отправке двоичной информации на ваш терминал. Это не очень хорошая идея, если вы используете терминал, который интерпретирует выходной поток (например, VT / DEC или многие другие).

Кроме того, вы можете отправить свой файл trс помощью следующей команды:

tr '[\000-\011\013-\037\177-\377]' '.' <test.log | grep whatever

Это превратит все, что меньше пробела (кроме новой строки) и больше 126, в .символ, оставив только печатные формы.


Если вы хотите, чтобы каждый "недопустимый" символ был заменен другим, вы можете использовать что-то вроде следующей программы на C, классического стандартного входного фильтра:

#include<stdio.h>
int main (void) {
    int ch;
    while ((ch = getchar()) != EOF) {
        if ((ch == '\n') || ((ch >= ' ') && (ch <= '~'))) {
            putchar (ch);
        } else {
            printf ("{{%02x}}", ch);
        }
    }
    return 0;
}

Это даст вам {{NN}}, где NNнаходится шестнадцатеричный код символа. Вы можете просто настроить printfлюбой стиль вывода, который хотите.

Вы можете увидеть эту программу в действии здесь, где она:

pax$ printf 'Hello,\tBob\nGoodbye, Bob\n' | ./filterProg
Hello,{{09}}Bob
Goodbye, Bob
paxdiablo
источник
Этот метод отображает все двоичные символы в один и тот же '.' условное обозначение. Есть ли другой метод сопоставления их с читаемыми символами?
Daniel YC Lin
Конечно, вы можете запустить его через другую программу фильтрации, одну из которых я предоставил в обновлении.
paxdiablo
1
Думаю tr '[:cntrl:] '.'лучше. И это должно быть \000-\010\013\014\016-\037\177-\377'в вашем синтаксисе tr.
Daniel YC Lin
2
После тестирования, tr '[\000-\010\013\014\016-\037\177-\377]' '_'работоспособно, cntrl не подходит для моего случая.
Daniel YC Lin
2
Вы можете сохранить catшаг за трубопроводами grep --textв trа не наоборот. Это также позволяет вам использовать grep для нескольких файлов и сохранять ссылку на имя файла в выводе.
aaaantoine 07
33

Вы можете использовать "строки" для извлечения строк из двоичного файла, например

strings binary.file | grep foo
moodywoody
источник
Сработал для меня хорошо, поскольку источником был журнал отладки с UID в каждой строке. Спасибо.
mbrownnyc 06
у меня тоже сработало. Спасибо за Ваш ответ. Спас мой день :)
Шекхар
2
Я ценю ответ @paxdiablo, но за быстрый ответ и выполнение работы вы не можете винить это.
Wil
Пытался использовать решение paxdiablo, но оно не дало мне никаких результатов, которых я ожидал. @moodywoody ваше решение быстрое, простое и дает именно то, что мне нужно!
Justinhartman
20

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

grep --binary-files=text

Вы также можете захотеть добавить -o( --only-matching), чтобы не получить кучу бинарной тарабарщины, которая сломает ваш терминал.

AB
источник
может выводить двоичный мусор, который может иметь неприятные побочные эффекты, если вывод является терминалом и если драйвер терминала интерпретирует некоторые из них как команды.
Daniel YC Lin
Если вы используете --only-matching, и ваше регулярное выражение не соответствует произвольным двоичным данным, у вас не будет проблем.
AB
если регулярное выражение - «first. * end», а двоичные данные содержат шаблон «. *», это не может исправить мой процесс постобработки. В любом случае, спасибо.
Daniel YC Lin
16

Начиная с Grep 2.21, двоичные файлы обрабатываются иначе :

При поиске двоичных данных grep теперь может обрабатывать нетекстовые байты как терминаторы строки. Это может значительно повысить производительность.

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

  • использовать --text. Это гарантирует, что только символы новой строки будут терминаторами строки.

  • использовать --null-data. Это гарантирует, что только нулевые байты будут терминаторами строки.

Стивен Пенни
источник
5

grep -a заставит grep искать и выводить из файла, который grep считает двоичным. grep -a re test.log

Кевин Бакс
источник
3

Как уже сказал Джеймс Селвакумар, свое grep -aдело. -a или --text заставляет Grep обрабатывать входной поток как текст. См. Страницу руководства http://unixhelp.ed.ac.uk/CGI/man-cgi?grep

пытаться

cat test.log | grep -a somestring
DerKnorr
источник
2

ты можешь сделать

strings test.log | grep -i

это преобразует вывод в виде читаемой строки в grep.

Mrid
источник
0

Вы также можете попробовать инструмент Word Extractor . Word Extractor можно использовать с любым файлом на вашем компьютере для отделения строк, содержащих человеческий текст / слова, от двоичного кода (приложения exe, библиотеки DLL).

MattCollW
источник
В моем случае мне не нужен экстрактор слов, мне нужно сохранить номер строки.
Daniel YC Lin
0

Вот что я использовал в системе, в которой не была установлена ​​команда "strings"

cat yourfilename | tr -cd "[:print:]"

Это печатает текст и удаляет непечатаемые символы одним махом, в отличие от "cat -v filename", который требует некоторой постобработки для удаления ненужных вещей. Обратите внимание, что некоторые двоичные данные могут быть распечатаны, поэтому между хорошими вещами вы все равно получите тарабарщину. Я думаю, что строки тоже убирают эту тарабарщину, если вы можете это использовать.

Muurder
источник