Come raccogliere le statistiche sull'occorrenza di byte nel file binario?


12

Mi piacerebbe sapere l'equivalente di

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

presentato in /programming/4174113/how-to-gather-characters-usage-statistics-in-text-file-using-unix- comandi per la produzione di statistiche sull'uso dei caratteri in file di testo per il conteggio dei file binari byte semplici anziché caratteri, ovvero l'output dovrebbe essere sotto forma di

18383 57
12543 44
11555 127
 8393 0

Non importa se il comando impiega tanto quanto quello di riferimento per i caratteri.

Se applico il comando per i caratteri ai file binari, l'output contiene statistiche per lunghe sequenze arbitrarie di caratteri non stampabili (non cerco spiegazioni per questo).

Risposte:


8

Con GNU od:

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

O in modo più efficiente con perl(genera anche un conteggio (0) per i byte che non si verificano):

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

Per poter riconoscere correttamente i numeri nella prima riga, ho dovuto aggiungere rispettivamente | sort -ne | sort -n -rper l'ordine decrescente (l'ordinamento non faceva parte della domanda). L'ordinamento potrebbe essere fatto meglio ...
Karl Richter,

Sembra un po 'eccessivo dover ordinare l'intero file, ma ha funzionato bene per me.
Michael Anderson,

Buon punto @Karl, anche se non richiesto, usare sort -nqui ha molto più senso. Risposta aggiornata
Stéphane Chazelas,

4

Per file di grandi dimensioni l'utilizzo dell'ordinamento sarà lento. Ho scritto un breve programma in C per risolvere il problema equivalente ( vedi questa sintesi per Makefile con i test ):

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

utilizzo:

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

Hai un test? Non ci sono commenti nel codice. In generale non è una buona idea usare codice non testato e pubblicare codice non testato o non commentato, indipendentemente dalla pratica comune. La possibilità di rivedere le revisioni è anche limitata su questa piattaforma, si consideri una piattaforma di hosting di codice esplicito.
Karl Richter,

I test di @KarlRichter sono stati una buona idea da aggiungere. Ho trovato la vecchia versione soffocata dai caratteri "\ 0". Questa versione dovrebbe funzionare (supera almeno alcuni test di base).
Bjoern Dahlgren,

fgetsottiene una linea, non un buffer pieno. Stai eseguendo la scansione del buffer completo da 4096 byte per ogni riga letta da stdin. Hai bisogno freadqui, no fgets.
Stéphane Chazelas,

@ StéphaneChazelas great - non sapevo di fread (raramente faccio I / O da C). esempio aggiornato per usare invece fread.
Bjoern Dahlgren,

Ho aggiunto un ifblocco attorno alle istruzioni printf, che rende l'output più leggibile se non si verificano alcuni byte nel file di input: gist.github.com/martinvonwittich/…
Martin von Wittich,

3

Come media, sigma e CV sono spesso importanti quando si giudicano i dati statistici del contenuto dei file binari, ho creato un programma cmdline che rappresenta graficamente tutti questi dati come un cerchio ASCII di deviazioni di byte da sigma.
http://wp.me/p2FmmK-96
Può essere utilizzato con grep, xargs e altri strumenti per estrarre statistiche. inserisci qui la descrizione dell'immagine


1

Il recodeprogramma può farlo rapidamente anche per file di grandi dimensioni, sia per le statistiche di frequenza sia per i byte o per i caratteri di vari set di caratteri. Ad esempio per contare le frequenze di byte:

$ 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

Attenzione : specifica il tuo file da ricodificare come input standard, altrimenti lo sostituirà silenziosamente con le frequenze dei caratteri!

Utilizzare recode utf-8/..count-characters < fileper trattare il file di input come utf-8. Sono disponibili molti altri set di caratteri e non funzioneranno se il file contiene caratteri non validi.


0

Questo è simile alla odrisposta di Stephane ma mostra il valore ASCII del byte. Inoltre è ordinato per frequenza / numero di occorrenze.

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

Non penso che questo sia efficace poiché molti processi sono stati avviati, ma è utile per singoli file, in particolare file di piccole dimensioni.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.