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


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.