Як зібрати статистику появи байтів у бінарний файл?


12

Я хотів би знати еквівалент

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

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

18383 57
12543 44
11555 127
 8393 0

Не має значення, чи команда займає стільки, скільки посилається на символи.

Якщо я застосую команду для символів до двійкових файлів, вихід містить статистику для довільних довгих послідовностей недрукованих символів (я не шукаю пояснення для цього).

Відповіді:


8

З GNU od:

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

Або більш ефективно за допомогою perl(також виводиться кількість (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-байтний повний буфер для кожного рядка, прочитаного з stdin. Вам потрібно freadтут, ні fgets.
— Стефан Шазелас

@ StéphaneChazelas чудовий - не знав про фрейд (рідко роблю I / O від C). оновлений приклад, щоб використовувати замість нього fread.
— Бьорн Далгрен

Я додав ifблок навколо операторів printf, що робить результат більш читабельним, якщо у вхідному файлі не з’являються деякі байти: gist.github.com/martinvonwittich/…
— Martin von Wittich

3

Оскільки середнє значення сигми та резюме часто є важливим при оцінці статистичних даних про вміст бінарних файлів, я створив програму cmdline, яка відображає всі ці дані у вигляді кола ascii байтових відхилень від sigma.
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. Доступно багато інших наборів символів, і він вийде з ладу, якщо файл містить незаконні символи.


1

Це схоже на відповідь Стефана, odале він показує значення ASCII байта. Він також сортується за частотою / кількістю випадків.

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

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

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