Как собрать статистику появления байтов в двоичном файле?


12

Я хотел бы знать эквивалент

cat inputfile | sed 's/\(.\)/\1\n/g' | sort | uniq -c

представленные в /programming/4174113/how-to-gather-characters-usage-statistics-in-text-file-using-unix-команды для создания статистики использования символов в текстовых файлах для подсчета двоичных файлов простые байты вместо символов, т.е. вывод должен быть в виде

18383 57
12543 44
11555 127
 8393 0

Неважно, если команда занимает столько времени, сколько указано для символов.

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

Ответы:


8

С GNU od:

od -vtu1 -An -w1 my.file | sort -n | uniq -c

Или более эффективно с perl(также выводит count (0) для байтов, которые не встречаются):

perl -ne 'BEGIN{$/ = \4096};
          $c[$_]++ for unpack("C*");
          END{for ($i=0;$i<256;$i++) {
              printf "%3d: %d\n", $i, $c[$i]}}' my.file

Для того, чтобы числа в первой строке были правильно распознаны, мне нужно было добавить | sort -nи | sort -n -rпо убыванию соответственно (сортировка не была частью вопроса). Сортировка могла бы быть лучше ...
— Карл Рихтер

Кажется, немного излишне сортировать весь файл, но у меня все получилось.
— Майкл Андерсон

Хороший вопрос @Karl, хотя и не запрашивается, использование sort -nздесь имеет гораздо больше смысла. Ответ обновлен.
— Стефан Шазелас

4

Для больших файлов использование сортировки будет медленным. Я написал короткую программу на C для решения эквивалентной проблемы ( см. Эту суть Makefile с тестами ):

#include <stdio.h>

#define BUFFERLEN 4096

int main(){
    // This program reads standard input and calculate frequencies of different
    // bytes and present the frequences for each byte value upon exit.
    //
    // Example:
    //
    //     $ echo "Hello world" | ./a.out
    //
    // Copyright (c) 2015 Björn Dahlgren
    // Open source: MIT License

    long long tot = 0; // long long guaranteed to be 64 bits i.e. 16 exabyte
    long long n[256]; // One byte == 8 bits => 256 unique bytes

    const int bufferlen = BUFFERLEN;
    char buffer[BUFFERLEN];
    int i;
    size_t nread;

    for (i=0; i<256; ++i)
        n[i] = 0;

    do {
        nread = fread(buffer, 1, bufferlen, stdin);
        for (i = 0; i < nread; ++i)
            ++n[(unsigned char)buffer[i]];
        tot += nread;
    } while (nread == bufferlen);
    // here you may want to inspect ferror of feof

    for (i=0; i<256; ++i){
        printf("%d ", i);
        printf("%f\n", n[i]/(float)tot);
    }
    return 0;
}

использование:

gcc main.c
cat my.file | ./a.out

У тебя есть тест? Там нет комментариев в коде. Как правило, не рекомендуется использовать непроверенный и публиковать непроверенный или незакомментированный код, независимо от того, является ли это обычной практикой. Возможность просмотра ревизий также ограничена на этой платформе, рассмотрим платформу для размещения явного кода.
— Карл Рихтер

Хорошей идеей было добавить тесты @KarlRichter. Я нашел старую версию, заглушенную символами '\ 0'. Эта версия должна работать (как минимум, проходит несколько базовых тестов).
— Бьерн Дальгрен

fgetsполучает строку, а не полный буфер. Вы сканируете 4096-байтовый полный буфер для каждой строки, считываемой из стандартного ввода. Вам нужно freadздесь, а не fgets.
— Стефан Шазелас

@ StéphaneChazelas здорово - не знал о хладнокровии (редко делают ввод / вывод из C). обновлен пример использования вместо fread.
— Бьерн Дальгрен

Я добавил ifблок вокруг операторов printf, который делает вывод более читабельным, если во входном файле нет байтов
— Martin von Wittich

3

Таким образом, сигма и CV часто важны при оценке статистических данных содержимого бинарных файлов. Я создал программу cmdline, которая отображает все эти данные в виде круга отклонений байтов от сигмы ascii.
http://wp.me/p2FmmK-96
Может использоваться с grep, xargs и другими инструментами для извлечения статистики. введите описание изображения здесь


1

recodeПрограмма может сделать это быстро , даже для больших файлов, либо статистики частот либо для байт или для символов различных наборов символов. Например, чтобы посчитать частоты байтов:

$ echo hello there > /tmp/q
$ recode latin1/..count-characters < /tmp/q
1  000A LF   1  0020 SP   3  0065 e    2  0068 h    2  006C l    1  006F o
1  0072 r    1  0074 t

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

Используйте recode utf-8/..count-characters < fileдля обработки входного файла как utf-8. Доступно много других наборов символов, и он не будет работать, если файл содержит недопустимые символы.


0

Это похоже на odответ Стефана, но показывает значение ASCII байта. Он также сортируется по частоте / количеству случаев.

xxd -c1 my.file|cut -c10-|sort|uniq -c|sort -nr

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.