Bagaimana cara mengumpulkan statistik kemunculan byte dalam file biner?

12

Saya ingin tahu yang setara

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

disajikan dalam /programming/4174113/how-to-gather-characters-usage-statistics-in-text-file-using-unix-commands untuk pembuatan statistik penggunaan karakter dalam file teks untuk penghitungan file biner byte sederhana alih-alih karakter, yaitu output harus dalam bentuk

18383 57
12543 44
11555 127
 8393 0

Tidak masalah jika perintah memakan waktu selama yang direferensikan untuk karakter.

Jika saya menerapkan perintah untuk karakter ke file biner, output berisi statistik untuk urutan panjang karakter yang tidak diinginkan yang sewenang-wenang (saya tidak mencari penjelasan untuk itu).

Karl Richter
sumber

Jawaban:

8

Dengan GNU od:

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

Atau lebih efisien dengan perl(juga menampilkan hitungan (0) untuk byte yang tidak terjadi):

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
sumber
Untuk mendapatkan angka-angka di baris pertama yang dikenali dengan benar, saya harus menambahkan | sort -ndan | sort -n -runtuk urutan menurun masing-masing (pengurutan bukan bagian dari pertanyaan). Penyortiran mungkin dilakukan dengan lebih baik ...
Karl Richter
Tampaknya sedikit berlebihan harus mengurutkan seluruh file, tetapi berhasil OK untuk saya.
Michael Anderson
Poin bagus @Karl, meskipun tidak diminta, menggunakan di sort -nsini jauh lebih masuk akal. Jawaban diperbarui.
Stéphane Chazelas
4

Untuk file besar menggunakan sort akan lambat. Saya menulis program C singkat untuk menyelesaikan masalah yang setara ( lihat intisari Makefile dengan tes ini ):

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

pemakaian:

gcc main.c
cat my.file | ./a.out
Bjoern Dahlgren
sumber
Apakah kamu memiliki tes? Tidak ada komentar dalam kode. Secara umum bukan ide yang baik untuk menggunakan kode yang belum diuji dan menerbitkan yang belum diuji atau tidak - tidak peduli apakah itu praktik umum. Kemungkinan untuk meninjau revisi juga terbatas pada platform ini, pertimbangkan platform hosting kode eksplisit.
Karl Richter
Tes @KarlRichter adalah ide bagus untuk ditambahkan. Saya menemukan versi lama tersedak karakter '\ 0'. Versi ini akan berfungsi (setidaknya lulus beberapa tes dasar).
Bjoern Dahlgren
fgetsmendapat garis, bukan buffer-penuh. Anda memindai buffer penuh 4096-byte untuk setiap baris yang dibaca dari stdin. Anda perlu di freadsini, bukan fgets.
Stéphane Chazelas
@ StéphaneChazelas hebat - tidak tahu ketakutan (jarang I / O dari C). contoh diperbarui untuk menggunakan ketakutan sebagai gantinya.
Bjoern Dahlgren
Saya telah menambahkan ifblok di sekitar pernyataan printf, yang membuat output lebih mudah dibaca jika beberapa byte tidak muncul di file input: gist.github.com/martinvonwittich/…
Martin von Wittich
3

Sebagai maksudnya, sigma dan CV sering penting ketika menilai data statistik dari isi file biner, saya telah membuat program cmdline yang membuat grafik semua data ini sebagai lingkaran ascii dari byte byte dari sigma.
http://wp.me/p2FmmK-96
Dapat digunakan dengan grep, xargs dan alat lain untuk mengekstrak statistik. masukkan deskripsi gambar di sini

circulosmeos
sumber
1

The recodeProgram dapat melakukan ini dengan cepat bahkan untuk file besar, baik statistik frekuensi baik untuk byte atau karakter dari berbagai rangkaian karakter. Misalnya untuk menghitung frekuensi 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

Peringatan - tentukan file Anda untuk dikode ulang sebagai input standar, jika tidak maka diam-diam akan menggantinya dengan frekuensi karakter!

Gunakan recode utf-8/..count-characters < fileuntuk memperlakukan file input sebagai utf-8. Banyak set karakter lainnya tersedia, dan itu akan gagal jika file tersebut mengandung karakter ilegal.

nealmcb
sumber
0

Ini mirip dengan odjawaban Stephane tetapi ini menunjukkan nilai ASCII dari byte tersebut. Itu juga diurutkan berdasarkan frekuensi / jumlah kejadian.

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

Saya tidak berpikir ini efisien karena banyak proses dimulai tetapi bagus untuk file tunggal, terutama file kecil.

brendan
sumber