Як зібрати текстовий файл, який містить деякі двійкові дані?


122

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".
Даніель YC Лін

Відповіді:


67

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

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

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


5
Вирішив мою проблему. Дякую! Ось що man catговорить про -v:-v, --show-nonprinting use ^ and M- notation, except for LFD and TAB
tommy.carstensen

Зауважте, що це працює і в конвеєрі. Наприкладset | cat -v | grep variable
funroll

1
Навіщо використовувати це, якщо grep --text працює? Це здається набагато складнішим.
Майкл Хейфеле

grep --textне завжди працює; він поважає CTRL + D як файловий термінатор. Тож якщо у вас це є у вашому бінарному файлі, grep вийде рано.
Томмі


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

Цей метод відображення всіх бінарних знаків у однакові '. символ. Чи існує інший метод, який відображає їх до читабельних символів?
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 не підходить для мого випадку.
Даніель YC Лін

2
Ви можете зберегти catкрок, проклавши grep --textйого trзамість навпаки. Це також дозволяє збирати декілька файлів і зберігати посилання на ім'я файлу у висновку.
aaaantoine

33

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

strings binary.file | grep foo

Для мене добре працював, оскільки джерелом був журнал налагодження з UID у кожному рядку. Дякую.
mbrownnyc

добре працювали і для мене. Дякую за вашу відповідь. Врятував мій день :)
Шехар

2
Я вдячний за відповідь @paxdiablo, але за швидку відповідь і зайняття завданням ви не можете цього винуватити.
Віл

Намагався використовувати розчин paxdiablo, однак це не дало мені жодного результату, якого я очікував. @moodywoody ваше рішення швидко, просто і видає саме те, що мені потрібно!
Justinhartman

20

Ви можете змусити grep переглядати бінарні файли за допомогою:

grep --binary-files=text

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


може вивести бінарний сміття, що може мати неприємні побічні ефекти, якщо вихід є терміналом і якщо драйвер терміналу інтерпретує частину цього як команди.
Daniel YC Lin

Якщо ви використовуєте --only-matching, а ваш регулярний вираз не відповідає довільним двійкових даних, у вас не виникне проблем.
AB

якщо регулярний вираз є "перший. * кінець", а двійкові дані містяться у шаблоні ". *", він не може виправити процес моєї публікації. У будь-якому випадку, дякую.
Даніель YC Лін

16

Починаючи з Grep 2.21, бінарні файли трактуються по-різному :

Під час пошуку бінарних даних grep тепер може розглядати нетекстові байти як термінатори рядків. Це може значно підвищити продуктивність.

Отже, що відбувається зараз - це те, що з двійковими даними всі нетекстові байти (включаючи нові рядки) трактуються як термінатори рядків. Якщо ви хочете змінити цю поведінку, ви можете:

  • використання --text. Це забезпечить, що лише нові рядки є термінаторами лінії

  • використання --null-data. Це забезпечить, що лише нульові байти є термінаторами рядків


5

grep -a змусить grep шукати і виводити файл, який, на думку grep, є двійковим. grep - повторний тест.log


3

Як вже сказав Джеймс Сельвакумар, grep -aце робить трюк. -a або --текст змушує Грепа обробляти вхідний потік як текст. Див. Сторінку Manpage http://unixhelp.ed.ac.uk/CGI/man-cgi?grep

спробуйте

cat test.log | grep -a somestring

2

Ви можете зробити

strings test.log | grep -i

це перетворить подання виводу у вигляді читабельної рядки в греп.


0

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


У моєму випадку я не вимагаю витягування слів, мені потрібно зберегти номер рядка.
Даніель YC Лін

0

Ось що я використовував у системі, в якій не було встановлено команди "string"

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

Це друкує текст і видаляє недруковані символи одним махом, на відміну від "cat -v filename", який вимагає деякої післяобробки для видалення небажаних речей. Зауважте, що деякі бінарні дані можуть бути надруковані, тому ви все одно отримаєте певний обхід між корисними матеріалами. Я думаю, що струни також знімають цю хитрість, якщо ви можете це використовувати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.