LINUX.ORG.RU
ФорумAdmin

Условие для потока файла /dev/ttyusb /dev/usbmon0

 , ,


1

1

Добрый день, подскажите пожалуйста как реализовать скрипт, который сравнивал бы строки из вывода файла и выполнял действие при совпадении.

Например, постоянно выводятся данные через hexdump такого вида:

0000 0001 0000 0001 0000 0000 0000 0000
6a00 c400 0484 f010 f721 0100 4f00 0012
0000 0000 5800 cfac 1f15 0b00 7d00 00f5
0600 00f7 0000 00e8 0022 0003 0000 1649

И нужно через условие или как-то выполнить действие при совпадении строки:

if [[ hexdump /dev/usbmon0 == "0000 0001 0000 0001 0000 0000 0000 0000"]]
then
commands;
commands;
commands;
fi

В продолжении этой темы - Как считать любые данные с usb порта?

PS Пишите, что поправить если не понятно

А прийти в виде

XXXX XXXX 0000 0001 0000 0001 0000 0000
0000 0000 XXXX XXXX XXXX XXXX XXXX XXXX
оно не может?

В любом случае - лучше писать такое на Си а не на шеллах. Кода на полстраницы думаю.

А вообще работать такими методами с финансово-значимыми устройствами по-моему плохая идея, лучше всё-таки отреверсить до конца весь протокол и работать с ним, а не с магическими последовательностями байт.

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

А прийти в виде … оно не может?

Может если указать параметр hexdump, но это что-то поменяет? У вас есть решение для такого вида?

В любом случае - лучше писать такое на Си а не на шеллах. Кода на полстраницы думаю. Так то оно так, но в си я очень плох, поэтому дело такое :(

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

Всмысле «указать параметр»? Я имею ввиду что в твоей постановке задачи складывается впечатление, что эти «0000 0001 0000 0001 0000 0000 0000 0000» всегда выровнены по границе 16 байт. Это действительно так? Если нет - может прийти сначала половина в конце одной строки, потом половина в начале следующей, и методом сравнения строк, который ты хочешь использовать, ты эту последовательность на заметишь.

Так то оно так, но в си я очень плох, поэтому дело такое :(

Ну тогда хотя бы на пхп каком-нить. И не сравнивая строки дампа, а сравнивая байты. Так то дело конечно твоё, но делать это через шелл ведёт к риску что где-то когда-то получиться совсем не то, что хочешь и поиметь потом финансовых претензий от клиентов.

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

Да, получается, что второй вариант, что может происходить смещение на половину:

То так

c8bc 19b2 fbfc 8000 c8bc 19b2 de05 b621

то так

c8bc 19b2 de05 b621 1a42 8123 0080 0000

Ну тогда хотя бы на пхп каком-нить

Php думаю будет предпочтительней Данные будут на локальный сайт отправлятся и там обрабатываться печать, скан, ксерокопия

SaintAnd
() автор топика
Последнее исправление: SaintAnd (всего исправлений: 2)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void) {
    const char *str = "c8bc19b2de05b621";
    int str_length = strlen(str);
    int bytes_count = str_length / 2;

    unsigned char buffer[bytes_count];
    for (int i = 0; i < bytes_count; ++i) {
        sscanf(str + 2 * i, "%2hhx", &buffer[i]);
    }

    FILE *f = fopen("infile.txt", "rb");
    if (f == NULL) {
        perror("Cannot open file:");
        return 1;
    }
    size_t file_buf_len = 128, counter = 0;
    char file_buf[file_buf_len];
    fgets(file_buf, sizeof(file_buf), f);
    for (int i = 0; i < file_buf_len; i++) {
        if (bytes_count + i <= file_buf_len) {
            for (int j = 0; j < bytes_count; j++) {
                unsigned char file_byte;
                sscanf(file_buf + i + 2 * j, "%2hhx", &file_byte);
                if ((unsigned char)buffer[j] == (unsigned char)file_buf[i + j]) {
                    counter++;
                } else {
                    counter = 0;
                    break;
                }
            }
            if (counter == bytes_count) {
                printf("Found str on position %d\n", i);
                return EXIT_SUCCESS;
            }
        } else {
            puts("Couldn't find str in file");
            return EXIT_FAILURE;
        }
    }
}
$ echo "00000000c8bc19b2de05b62100000000" | xxd -r -p > infile.txt
$ hexdump -C infile.txt
00000000  00 00 00 00 c8 bc 19 b2  de 05 b6 21 00 00 00 00  |...........!....|
00000010
$ cc tmp.c && ./a.out
Found str on position 4
iron ★★★★★
()
Ответ на: комментарий от iron

Что-то ты раз за разом печалишь в своих способах написания программ на Си. Объявления перемешаны с кодом, VLA не к месту, fgets вместо fread, отсутствие проверки кодов возврата, и вообще странная логика работы.

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

Что-то ты раз за разом печалишь

«Я не волшебник, я только учусь» (с) :)

Чуток причесал.

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

int main(void) {
    const char *str = "c8bc19b2de05b621";
    const int bytes_count = strlen(str) / 2;
    size_t counter = 0;
    const size_t read_max = 128;
    unsigned char file_buf[read_max];

    unsigned char buffer[bytes_count];
    for (int i = 0; i < bytes_count; ++i) {
        sscanf(str + 2 * i, "%2hhx", &buffer[i]);
    }

    FILE *f = fopen("infile.txt", "rb");
    if (f == NULL) {
        perror("Cannot open file:");
        return EXIT_FAILURE;
    }

    size_t n_read = fread(file_buf, 1, read_max, f);

    if (n_read >= bytes_count) {
        for (int i = 0; i < n_read - bytes_count; i++) {
            for (int j = 0; j < bytes_count; j++) {
                if (buffer[j] == file_buf[i + j]) {
                    counter++;
                } else {
                    counter = 0;
                    break;
                }
            }
            if (counter == bytes_count) {
                printf("Found str on position %d\n", i);
                return EXIT_SUCCESS;
            }
        }
    }

    puts("Couldn't find str in file");
    return EXIT_FAILURE;
}

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

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

Пишу как могу(. Понимаю, что тем кто пишет на сях мой код как серпом по яйцам)

Что есть то есть. Думается мне что на самом деле Вы хотите getline() + memcmp() или (в худшем случае) getline() + strstr(), а не вот это вот всё. В плюсовом варианте код будет попроще (и, при прочих равных - понадёжнее). Удачи Вам (чувствую - пригодится) :)

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

Думается мне что на самом деле Вы хотите getline()

getline() аллоцирует память в хипе. А это в данном случае избыточно.

memcmp()

Спасибо за подсказку. С ним действительно проще нежели байтики теребить.

Вот что получилось.

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

int main(void) {
    const char *str = "c8bc19b2de05b621";
    const int bytes_count = strlen(str) / 2;
    const size_t read_max = 128;
    char file_buf[read_max];

    unsigned char buffer[bytes_count];
    for (int i = 0; i < bytes_count; ++i) {
        sscanf(str + 2 * i, "%2hhx", &buffer[i]);
    }

    FILE *f = fopen("infile.txt", "rb");
    if (!f) {
        perror("Cannot open file:");
        return EXIT_FAILURE;
    }

    size_t n_read = fread(file_buf, 1, read_max, f);

    if (n_read >= bytes_count) {
        for (int i = 0; i < n_read - bytes_count; i++) {
            if (memcmp((const void *)&file_buf[i], buffer, bytes_count) == 0) {
                printf("Found str on position %d\n", i);
                return EXIT_SUCCESS;
            }
        }
    }

    puts("Couldn't find str in file");
    return EXIT_FAILURE;
}
iron ★★★★★
()
Ответ на: комментарий от iron

getline() аллоцирует память в хипе. А это в данном случае избыточно.

А у Вас вариантов то и нет, unless размеры строк в файле фиксированны / ограничены сверху. Заметьте - аллокации происходят только если необходимо, в противном случае существующий буфер при последующих чтениях реюзается.

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

unless размеры строк в файле фиксированны / ограничены сверху

Ок. Вот вариант чтения произвольной длины строки из файла с использованием getline().

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

int main(void) {
    const char *str = "c8bc19b2de05b621";
    const int bytes_count = strlen(str) / 2;
    size_t read_min = 128;
    char *file_buf = NULL;

    unsigned char buffer[bytes_count];
    for (int i = 0; i < bytes_count; ++i) {
        sscanf(str + 2 * i, "%2hhx", &buffer[i]);
    }

    FILE *f = fopen("infile.txt", "rb");
    if (!f) {
        perror("Cannot open file:");
        return EXIT_FAILURE;
    }

    file_buf = malloc(sizeof(char) * read_min);
    size_t n_read = getline(&file_buf, &read_min, f);

    if (n_read >= bytes_count) {
        for (int i = 0; i < n_read - bytes_count; i++) {
            if (memcmp((const void *)&file_buf[i], buffer, bytes_count) == 0) {
                printf("Found str on position %d\n", i);
                free(file_buf);
                return EXIT_SUCCESS;
            }
        }
    }

    puts("Couldn't find str in file");
    free(file_buf);
    return EXIT_FAILURE;
}

В принципе, malloc() можно оттуда вообще выкинуть, так как getline() сам зааллоцирует сколько нужно.

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

В принципе, malloc() можно оттуда вообще выкинуть, так как getline()

Не только можно, а нужно - не мешайте getline() делать его работу. И таки Вам strstr() нужен - Вы только что влетели на O(N^2) там где O(N) точно хватает.

ПыСы. И зачем я это делаю?

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

И таки Вам strstr() нужен

Мы же читаем бинарные данные в которых может встречаться '\0'. Следовательно, strstr() тут не к месту. Остается два варианта: либо теребить байтики, либо memcpy(). Вопрос лишь в том, какой вариант более оптимальный по производительности. Мне кажется они одинаковы.

ПыСы. И зачем я это делаю?

Ну интересно же). И довольно познавательно.

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

Мы же читаем бинарные данные в которых может встречаться ‘\0’. Следовательно, strstr() тут не к месту.

Тогда «ручками» memchr() + memcmp(), делов то. Но точно не memcmp() в цикле на полную длину со сдвигом в 1.

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

Тогда «ручками» memchr() + memcmp()

Согласен, разумно.

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

int main(void) {
    const char *str = "c8bc19b2de05b621";
    const int bytes_count = strlen(str) / 2;
    size_t read_min = 128;
    char *file_buf = NULL;

    unsigned char buffer[bytes_count];
    for (int i = 0; i < bytes_count; ++i) {
        sscanf(str + 2 * i, "%2hhx", &buffer[i]);
    }

    FILE *f = fopen("infile.txt", "rb");
    if (!f) {
        perror("Cannot open file:");
        return EXIT_FAILURE;
    }

    size_t n_read = getline(&file_buf, &read_min, f);

    char *ptr = memchr(file_buf, buffer[0], n_read);
    if (n_read >= bytes_count && ptr) {
        if (memcmp(ptr, buffer, bytes_count) == 0) {
            printf("Found str on position %lu\n", (size_t)(ptr - file_buf));
            free(file_buf);
            return EXIT_SUCCESS;
        }
    }

    puts("Couldn't find str in file");
    free(file_buf);
    return EXIT_FAILURE;
}
iron ★★★★★
()
Ответ на: комментарий от iron

Мы же читаем бинарные данные в которых может встречаться ‘\0’.

Тогда «ручками» memchr() + memcmp(), делов то.

Согласен, разумно.

Что я нанёс (а никто и не поправил): если там действительно бинарник (а не выхлоп hexdump’а) забудьте всё что я раньше сказал про getline() - читать им бинарники крайне не рекомендуется.

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

если там действительно бинарник (а не выхлоп hexdump’а) забудьте всё что я раньше сказал про getline()

Та я и сам провтыкал(. Вспомнил о бинарных данных только в контексте strstr().

Возвращаемся к истокам)

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

int main(void) {
    const char *str = "c8bc19b2de05b621";
    const int bytes_count = strlen(str) / 2;
    const size_t read_max = 128;
    char file_buf[read_max];

    unsigned char buffer[bytes_count];
    for (int i = 0; i < bytes_count; ++i) {
        sscanf(str + 2 * i, "%2hhx", &buffer[i]);
    }

    FILE *f = fopen("infile.txt", "rb");
    if (!f) {
        perror("Cannot open file:");
        return EXIT_FAILURE;
    }

    size_t n_read = fread(file_buf, 1, read_max, f);

    char *ptr = memchr(file_buf, buffer[0], n_read);
    if (n_read >= bytes_count && ptr) {
        if (memcmp(ptr, buffer, bytes_count) == 0) {
            printf("Found str on position %lu\n", (size_t)(ptr - file_buf));
            return EXIT_SUCCESS;
        }
    }

    puts("Couldn't find str in file");
    return EXIT_FAILURE;
}
iron ★★★★★
()
Ответ на: комментарий от iron

Ты лучший, пожал бы руку за твой энтузиазм

▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
▒▒▓▓▓▓▒▓▓▒▒▓▓▒▒▓▓▓▓▒▒▒▓▓▓▓▒▒▓▓▓▓▒▒
▒▓▓▒▒▒▒▓▓▒▒▓▓▒▓▓▒▒▓▓▒▓▓▒▒▒▒▓▓▒▒▓▓▒
▒▒▓▓▓▒▒▓▓▒▒▓▓▒▓▓▓▓▓▒▒▓▓▓▓▒▒▓▓▓▓▓▓▒
▒▒▒▒▓▓▒▓▓▒▒▓▓▒▓▓▒▒▒▒▒▓▓▒▒▒▒▓▓▒▓▓▒▒
▒▓▓▓▓▒▒▒▓▓▓▓▒▒▓▓▒▒▒▒▒▒▓▓▓▓▒▓▓▒▒▓▓▒
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒

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

Возвращаемся к истокам)

  1. нужен цикл вокруг memchr() + memcmp(), подумайте о файле с содержимым «01 01 02 03 04 …» и попытке в этом найти «01 02 03 04».
  2. если memchr() остановился слишком близко к концу буфера - memcmp() делать нельзя.
  3. я не знаю задумывался ли поиск только в первых 128 байтах, но скорее всего хотелось искать во всем файле - и тогда нужен цикл вокруг fread(), причём нужно очень аккуратно смотреть на «хвосты»: как только memchr() остановился ближе к концу буфера чем длинна needle - проще всего двинуть (memmove()) «хвост» в начало буфера и читать из файла дальше. Это можно продолжать оптимизировать, но на коротких needle «овчинка выделки не стоит», имхо.
  4. Не знаю откуда циферка в 128 байт взялась - для обычных файлов «маловато будет», что-то мне подсказывает Вы на самом деле non-blocking read хотите с select(). Но думаю что на этом этапе с non-blocking / async IO Вам разобраться будет сложновато, даже с самой концепцией.

ПыСы. Мне бы очень не хотелось чтобы хоть что-то из того что я сказал воспринималось как какая-то извращённая форма издевательства - я честно помочь пытаюсь указывая на очевидные ляпы.

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

Все это логично и правильно. НО, автор топика сначала пишет о сравнении строк из вывода файла. Но при этом в предыдущей теме речь идет о считывании данных с USB устройства. В итоге не понятно откуда беруться данные. По сему, зачем сейчас «доить сферического коня в вакууме» с чтением файла, если в итоге читать нужно не с него. В выше представленных примерах есть концепт того, как можно выполнять поиск последовательности бинарных данных. Все остальное – уже детали.

Если топикстартер более подробнее расскажет откуда ему нужно доставать данные, то можно было бы по фану что-то придумать. А еще лучше, иметь возможность воспроизвести у себя подобный поток данных.

Но думаю что на этом этапе с non-blocking / async IO Вам разобраться будет сложновато

Если бы я писал для себя, я бы на входящий поток данных подцепил бы kqueue() фильтр и парсил бы данные по мере их поступления.

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

Все это логично и правильно.

Те ляпы на которые я указал - это логические ошибки которые приводят к неправильному поведению. Я даже не придираюсь к стилистике - оно тупо не работает (пока ещё).

Если бы я писал для себя, я бы на входящий поток данных подцепил бы kqueue()

Я не до конца понимаю к чему Вы ведёте - то что Вы до сих пор продемонстрировали от уровня «нам нужен kqueue» сильно далеко. Я уж молчу что оно BSD-specific (если мы об одном и том же).

ПыСы. И ссылка - битая, кстати.

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

Я не до конца понимаю к чему Вы ведёте

Я веду к тому, что не зная источник данных – невозможно подобрать оптимальный метод чтения с него. А вариантов может быть много: от тупого read() до aio_read(), epoll()/kqueue().

то что Вы до сих пор продемонстрировали от уровня «нам нужен kqueue» сильно далеко

kqueue() не является чем-то сложным и недостижимым. И тем более не является показателем уровня программерского мастерства.

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

kqueue() не является чем-то сложным и недостижимым.

Знаете как говорят - «не боги обжигают горшки». Конечно ничего сверх-естественного там нет. Но Вы хотя-бы безглючный (пусть и медленный) «бинарный» strstr() напишите для начала. А потом мы вернёмся к kqueue.

bugfixer ★★★★★
()
Последнее исправление: bugfixer (всего исправлений: 1)
#!/usr/bin/python
import os

file_name = '/dev/usbmon0'
hex_string = '0000 0001 0000 0001 0000 0000 0000 0000'
byte_string = bytes.fromhex(hex_string)

def действие():
    shell_commands = '''
        echo command_1
        echo command_2
        echo command_3
    '''
    os.system(shell_commands)

with open(file_name, 'rb') as f:
    window = b''
    while r := f.read(16):
        window = window[-15:] + r
        if byte_string in window:
            действие()
anonymous
()