Jak zebrać statystyki występowania bajtów w pliku binarnym?

12

Chciałbym poznać odpowiednik

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

przedstawione w /programming/4174113/how-to-gather-characters-usage-statistics-in-text-file-using-unix-commands do tworzenia statystyk użycia znaków w plikach tekstowych do liczenia plików binarnych proste bajty zamiast znaków, tzn. dane wyjściowe powinny mieć postać

18383 57
12543 44
11555 127
 8393 0

Nie ma znaczenia, czy polecenie trwa tak długo, jak polecenie określone dla znaków.

Jeśli zastosuję polecenie znaków do plików binarnych, dane wyjściowe będą zawierały statystyki dotyczące dowolnych długich sekwencji znaków, które nie mogą zostać wydrukowane (nie szukam tego wyjaśnienia).

Karl Richter
źródło

Odpowiedzi:

8

Z GNU od:

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

Lub wydajniej za pomocą perl(wyświetla również liczbę (0) dla bajtów, które nie występują):

perl -ne 'BEGIN{$/ = \4096};
          $c[$_]++ for unpack("C*");
          END{for ($i=0;$i<256;$i++) {
              printf "%3d: %d\n", $i, $c[$i]}}' my.file
Stéphane Chazelas
źródło
Aby poprawnie rozpoznać liczby w pierwszym rzędzie, musiałem odpowiednio dodać | sort -ni | sort -n -rdla porządku malejącego (sortowanie nie było częścią pytania). Sortowania można dokonać lepiej ...
Karl Richter
Wygląda na to, że trzeba przesadzić z całym plikiem, ale działało to dla mnie OK.
Michael Anderson,
Dobra uwaga @Karl, choć nie jest wymagana, użycie sort -ntutaj ma o wiele większy sens. Odpowiedź zaktualizowana.
Stéphane Chazelas,
4

W przypadku dużych plików użycie sortowania będzie wolne. Napisałem krótki program w C, aby rozwiązać równoważny problem ( zobacz poniższą listę dla Makefile z testami ):

#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;
}

stosowanie:

gcc main.c
cat my.file | ./a.out
Bjoern Dahlgren
źródło
Czy masz test? W kodzie nie ma komentarzy. Zasadniczo nie jest dobrym pomysłem używanie nieprzetestowanego i publikowanie nieprzetestowanego lub niezakomentowanego kodu - bez względu na to, czy jest to powszechna praktyka. Możliwość przeglądania poprawek jest również ograniczona na tej platformie, rozważ jawną platformę hostingową kodu.
Karl Richter
Testy @KarlRichter były dobrym pomysłem do dodania. Znalazłem starą wersję zadławioną znakami „\ 0”. Ta wersja powinna działać (przechodzi co najmniej kilka podstawowych testów).
Bjoern Dahlgren
fgetsdostaje linię, a nie bufor-pełny. Skanujesz pełny bufor o długości 4096 bajtów dla każdej linii odczytanej ze standardowego wejścia. Potrzebujesz freadtutaj, nie fgets.
Stéphane Chazelas,
@ StéphaneChazelas świetnie - nie wiedziałem o fread (rzadko czy I / O z C). zaktualizowany przykład użycia fread zamiast tego.
Bjoern Dahlgren
Dodałem ifblok wokół instrukcji printf, dzięki czemu dane wyjściowe są bardziej czytelne, jeśli w pliku wejściowym nie występują pewne bajty: gist.github.com/martinvonwittich/…
Martin von Wittich
3

Ponieważ sigma i CV są często ważne przy ocenie danych statystycznych dotyczących zawartości plików binarnych, stworzyłem program cmdline, który wyświetla wszystkie te dane jako ascii krąg bajtowych odchyleń od sigmy.
http://wp.me/p2FmmK-96
Można go używać z grep, xargs i innymi narzędziami do wyodrębniania statystyk. wprowadź opis zdjęcia tutaj

circulosmeos
źródło
1

recodeProgram może to zrobić szybko, nawet w przypadku dużych plików, albo statystyki częstotliwości zarówno dla bajtów lub znaków dla różnych zestawów znaków. Np. Zliczanie częstotliwości bajtów:

$ 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

Uwaga - określ plik do przekodowania jako standardowe wejście, w przeciwnym razie dyskretnie zastąpi go częstotliwościami znaków!

Służy recode utf-8/..count-characters < filedo traktowania pliku wejściowego jako utf-8. Dostępnych jest wiele innych zestawów znaków i zakończy się niepowodzeniem, jeśli plik zawiera jakiekolwiek niedozwolone znaki.

nealmcb
źródło
1

Jest to podobne do ododpowiedzi Stephane'a, ale pokazuje wartość bajtu ASCII. Jest również sortowane według częstotliwości / liczby wystąpień.

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

Nie sądzę, aby było to wydajne, ponieważ uruchomiono wiele procesów, ale jest dobre dla pojedynczych plików, szczególnie małych plików.

brendan
źródło