LINUX.ORG.RU
ФорумAdmin

Как заставить grep искать всё, кроме образца?

 


0

1

Этот вопрос вышел из прошлой темы, и увы остался не решённым.

Не подскажет ли всезнающий all, умеет ли grep или его аналог это вообще? Я искал в гугле, читал хабр, стек оверфлоу, посты на опеннете, но увы, самое важное видимо упустил.

ЗАДАЧА: Поиск прямо на устройстве /dev/sdX байт, отличных от образца.
ЗАЧЕМ: sd карта забита через dd нулями. Нужно быстро искать и выводить в формате xxd всё, что стало не ноль. Так я сразу увижу активность одной древней FS.

Пока могу только поискать конкретный байт в бинарном файле устройства:

sudo grep -obUaP "\x01" /dev/sde

Если попробую инвертировать выборку по v, и по идее увидеть всё, кроме образца, то не увижу ничего:

sudo grep -obUaPv "\x00" /dev/sde

Пробую отдельно через пайп - вообще без эффекта:

sudo xxd /dev/sde | grep -v "\x00"

Жалею, что hextedit не позволяет скрывать строки по маске \x00. Но хочется именно получать результат сразу в консоль без интерактива.

ЧЯДНТ?

Ответ на: комментарий от i-rinat

Я это пробовал, но не очень понял, что это вообще:

           Canonical hex+ASCII display. Display the input offset in hexadecimal, followed by sixteen space-separated, two-column, hexadecimal bytes,  
           followed by the same sixteen bytes in %_p format enclosed in '|' characters. Invoking the program as hd implies this option.
sudo hexdump -C /dev/sde
00000000  01 00 00 00 02 00 00 00  03 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
01ea0000

Вначале устройства у меня стоят маркеры 01, 02, 03. Чтобы было что искать. Но на выдаче мы видим кроме первой и вторую пустую строку. Затем звёздочку и циферку. Очень интересно, но не понятно.

hikikomori ★★★
() автор топика
Ответ на: комментарий от hikikomori

Звёздочка вместо кучи нулей. Циферка — последнее смещение.

А grep по строкам работает, если ввод сначала как-то по строкам порезать, то с помощью -v что-то можно будет придумать.

mky ★★★★★
()

Нужно быстро искать и выводить в формате xxd всё, что стало не ноль

Тебе сказали пользуй hexdump

под * он пропускает одинаковые (здесь нулевые строки), так что покажет не нулевые

futurama ★★★★★
()
Ответ на: комментарий от hikikomori

Звёздочка означает, что следующие строчки повторяются. Это не обязательно нули. Например:

$ yes "123456789012345" | head -200 | hexdump -C
00000000  31 32 33 34 35 36 37 38  39 30 31 32 33 34 35 0a  |123456789012345.|
*
00000c80
$ 

yes генерирует повторяющиеся 16 байт, а hexdump прячет все повторяющиеся строки.

В твоём случае это нули, да.

i-rinat ★★★★★
()
Ответ на: комментарий от i-rinat

Да, но тогда я пропущу участок, который будет забит FF. В моём случае это важно. Я должен найти любые блоки отличные от #00. @mky, @futurama - поэтому вопрос актуален.

hikikomori ★★★
() автор топика
Последнее исправление: hikikomori (всего исправлений: 1)

А в каком виде хочешь получать результат? Вывод в консоль всех изменений не слишком подходит для анализа, как по мне.

izzholtik ★★★
()

Пробую отдельно через пайп - вообще без эффекта:
sudo xxd /dev/sde | grep -v «\x00»

Вот так с эффектом:

xxd -g16 /dev/sde | grep -v "000000000000000"

должно быть )

Toxo2 ★★★★
()
Ответ на: комментарий от izzholtik

Не, можно конечно сравнивать файлы образы текущий и пустой после забивания нулями:

colordiff <(unidump testwidth.txt) <(unidump testwidth2.txt)

но это долго, и каждый раз делать сперва слепок.

Мне нужно оперативно и быстро отслеживать изменения в начале диска - по разделам и таблицам fat.

В консоль - универсалшьный вариант, надо будет в лог, всегда можно > перенаправить.

hikikomori ★★★
() автор топика
Ответ на: комментарий от Toxo2

Почему именно 15 нулей?

Со смещением #60 у меня ещё пара контрольных не нулевых значений. Он их не нашёл. Если уменьшить кол-во нулей, то тоже ничего

$ sudo hexdump -C /dev/sde
00000000  01 00 00 00 02 00 00 00  03 00 00 00 00 00 00 00  |................|
00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000060  01 01 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
01ea0000
$ sudo xxd -g16 /dev/sde | grep -v "000000000000000"
00000000: 01000000020000000300000000000000  ................
hikikomori ★★★
() автор топика
Последнее исправление: hikikomori (всего исправлений: 1)
Ответ на: комментарий от hikikomori

Почему именно 15 нулей?

Потому что опечатался. Должно быть 16, конечно. Или

xxd -g 16 binary.dat | grep -v $(for i in {1..16}; do echo -n "0"; done)
чтобы не опечатываться, но кушать процессор лишний раз.

xxd переводит в строки по 16 символов, grep ищет эти строки. Должно работать.

Toxo2 ★★★★
()
Ответ на: комментарий от Toxo2

Всё равно нет 00000060 01 01

$ sudo xxd -g16 /dev/sde | grep -v "0000000000000000"
00000000: 01000000020000000300000000000000  ................
$ sudo xxd -g 16 /dev/sde | grep -v $(for i in {1..16}; do echo -n "0"; done)
00000000: 01000000020000000300000000000000  ................

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

hikikomori ★★★
() автор топика
Ответ на: комментарий от hikikomori

Всё равно нет

Потому что 15 - опечатался. А 16 - просто глупо ошибся.

xxd -g 16 же по два символа печатает, конечно. Т.е. надо искать и отбрасывать 32 нуля подряд, а не 16.

Т.е.

sudo xxd -g 16 /dev/sde | grep -v $(for i in {1..16}; do echo -n "00"; done)
например.

Toxo2 ★★★★
()
Последнее исправление: Toxo2 (всего исправлений: 1)
Ответ на: комментарий от hikikomori

Вот так ещё можно, наверное:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#define BUFLEN 16
char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Missing agrument.\n");
        return 1;
    }
    char buf[BUFLEN];
    char str_buf_hex[BUFLEN * 2 + 1] = {0};
    char str_buf[BUFLEN + 1] = {0};
    int f = open(argv[1], O_RDONLY);
    unsigned int offset = 0;
    if (f > 0)
    {
        while (1)
        {
            int b = read(f, buf, BUFLEN);
            if (b > 0)
            {
                int flag = 0;
                int i = 0, j = 0;
                for (; i < b; i++, j += 2)
                {
                    str_buf_hex[j] = hexx[(buf[i] >> 4) & 0xf];
                    str_buf_hex[j + 1] = hexx[buf[i] & 0xf];
                    (buf[i] < 32) ? str_buf[i] = '.' : (str_buf[i] = buf[i]);
                    if (buf[i] != 0)
                    {
                        flag = 1;
                    }
                }
                str_buf_hex[j] = 0;
                str_buf[i] = 0;
                if (flag)
                {
                    printf("%08lx: %s %s\n", offset, str_buf_hex, str_buf);
                }
                offset += b;
            }
            else
            {
                break;
            }
        }
        close(f);
    }
    else
    {
        printf("Unable to open %s\n", argv[1]);
    }
    return 0;
}
С парой строк спёртых из исходника xxd.

Toxo2 ★★★★
()
Ответ на: комментарий от hikikomori

тогда я пропущу участок, который будет забит FF

Нет.

i-rinat ★★★★★
()
Ответ на: комментарий от hikikomori

Ты до сих пор текст пытаешься выдрать? Кодировка текста там у тебя однобайтовая ведь, тогда можно взять дамп твоей фс и тупо заменить все байты что вне диапазона a-z-AZ + всякие !"№;%:?*( с табами и переводами строк заменить на ’ ’ пробелы. И ты получишь 4GB тектовый файл. Только вот я хз как твоя фс устроена и чего там с фрагментацией. Ну или читать побайтово и просто не показывать байты которые являются не символами, а остальное отображать как букафки. Простейшая сишная утилита сделает это, какая у тебя точно там кодировка текста?

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 2)
Ответ на: комментарий от LINUX-ORG-RU

Нет, с текстом я разобрался. Просто его выдирать неудобно, FS поддерживает сегментацию, и я не уверен, что все файлы непрерывные. Хотя на винте места много, предел размера раздела довольно низкий. Я решил создать и изучить новую FS на отдельной карте, затем через dd либо перетащу туда данные, либо восстанавлю запорченные таблицы разделов.

Кодировка DOS CP866. но побайтовое чтение это же очень долго будет.

hikikomori ★★★
() автор топика
Ответ на: комментарий от Toxo2

Пардон. Не мог остановиться. )
Что бы ни делать, лишь бы колодец не рыть. )

Переписал аккуратнее:

#include <stdio.h>
#include <stdlib.h>

#define BUFLEN 16
#define UNPRINTCHAR 32
#define BUFCOUNT 10000
#define OFFSETLEN 16
#define LINELEN (OFFSETLEN + 1 + BUFLEN * 2 + 1 + BUFLEN + 1)

char *hexx = "0123456789abcdef";

void ulltohex(unsigned long long n, char *s)
{
    for (int i = 16; i >= 0; i--)
    {
        s[i] = hexx[n & 0x0f];
        n = n >> 4;
    }
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        printf("Missing agrument.\n");
        return 1;
    }
    FILE *f = fopen(argv[1], "r");
    if (f > 0)
    {
        char *readbuf = malloc(BUFLEN * BUFCOUNT);
        if (readbuf != NULL)
        {
            unsigned long long offset = 0;
            static char line[LINELEN + 1];
            while (1)
            {
                size_t b_realread = fread(readbuf, 1, BUFLEN * BUFCOUNT, f);
                if (b_realread > 0)
                {
                    for (int c = 0; c < BUFCOUNT; c++)
                    {
                        size_t p_local = c * BUFLEN;
                        char *localbuf = &readbuf[p_local];
                        int pos_hex = OFFSETLEN + 2;
                        int pos_sym = OFFSETLEN + 2 + BUFLEN * 2 + 1;
                        int sum_check = 0;
                        for (int i = 0; i < BUFLEN; i++)
                        {
                            if (b_realread > (i + p_local))
                            {
                                line[pos_hex++] = hexx[(localbuf[i] >> 4) & 0xf];
                                line[pos_hex++] = hexx[localbuf[i] & 0xf];
                                line[pos_sym++] = (localbuf[i] < UNPRINTCHAR) ? '.' : localbuf[i];
                                sum_check += localbuf[i];
                            }
                            else
                            {
                                line[pos_hex++] = line[pos_hex++] = line[pos_sym++] = ' ';
                            }
                        }
                        if (sum_check != 0)
                        {
                            ulltohex(offset, line);
                            line[OFFSETLEN + 1] = line[OFFSETLEN + 1 + BUFLEN * 2 + 1] = ' ';
                            line[LINELEN] = '\n';
                            fputs(line, stdout);
                        }
                        offset += BUFLEN;
                    }
                }
                else
                {
                    break;
                }
            }
            free(readbuf);
        }
        else
        {
            printf("Unable to allocate memory\n");
        }
        fclose(f);
    }
    else
    {
        printf("Unable to open file %s\n", argv[1]);
    }
    return 0;
}
Но делает практически ровно то же, что и
xxd -g 16 ~/binary.dat | grep -v "00000000000000000000000000000000"

И примерно с той же эффективностью.

За исключением варианта с перенаправлением в /dev/null ) Тогда да, тогда для 2GB /dev/sda1 получается 9 секунд, против 1 минуты для xxd|grep ) Если таки писать в консоль - что там 4 минуты, что там 4 минуты в urxvt. И по 13 минут в xfce4-terminal, соответственно.

Хорошо поиграл в вашу игру, ТС, спасибо ).

Toxo2 ★★★★
()
Последнее исправление: Toxo2 (всего исправлений: 1)
Ответ на: комментарий от anc

ОТВЕТ СКОРЕЕ НОВИЧКАМ В ТРЕДЕ, чем вам.

Вы за совсем ССЗБ меня не держите. Я ВСЕГДА перед каждой операцией с веткой /dev/sdX сверяюсь по blkid или для более точной информации по

sudo parted /dev/sdX unit s p free

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

 ls /dev/disk/by-
by-id/        by-label/     by-partlabel/ by-partuuid/  by-path/      by-uuid/
hikikomori ★★★
() автор топика
Ответ на: комментарий от Toxo2

Ларчик просто открывался… В итоге причина, по которой я создал эту тему разрешилась более простым путём) Сгнил UDE шлейф с матери на ide to sd адаптер. Поэтому данные сперва портились при передаче, потом перестали поступать вовсе. Причём если подключать реальный ide hdd, то работало, а адаптеру не хватало. Заменил шлейф - увидел разделы и файлы без реставрации. Осталось убитый загрузчик починить, но я для этого даже dd мучать не буду, а средствами ОС висьмидитки решу прямо на спектруме)

Рад ещё одному опыту, но жаль длительного простоя ретропк.

hikikomori ★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.