Làm thế nào để thu thập số liệu thống kê xuất hiện byte trong tệp nhị phân?


12

Tôi muốn biết tương đương với

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

được trình bày trong /programming/4174113/how-to-gather-charerson-usage-statistic-in-text-file-USE-unix-commands để sản xuất số liệu thống kê sử dụng ký tự trong tệp văn bản để đếm tệp nhị phân byte đơn giản thay vì ký tự, tức là đầu ra phải ở dạng

18383 57
12543 44
11555 127
 8393 0

Sẽ không có vấn đề gì nếu lệnh mất chừng nào lệnh được tham chiếu cho các ký tự.

Nếu tôi áp dụng lệnh cho các ký tự cho các tệp nhị phân, đầu ra chứa các số liệu thống kê cho các chuỗi dài tùy ý của các ký tự không thể in được (tôi không tìm cách giải thích cho điều đó).

Câu trả lời:


8

Với GNU od:

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

Hoặc hiệu quả hơn với perl(cũng xuất ra số đếm (0) cho các byte không xảy ra):

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

Để có được các số trong hàng đầu tiên được nhận dạng chính xác, tôi phải thêm | sort -n| sort -n -rtheo thứ tự giảm dần tương ứng (sắp xếp không phải là một phần của câu hỏi). Sắp xếp có thể được thực hiện tốt hơn ...
Karl Richter

Có vẻ hơi quá mức khi phải sắp xếp toàn bộ tệp, nhưng làm việc tốt với tôi.
Michael Anderson

Điểm tốt @Karl, mặc dù không được yêu cầu, sử dụng sort -nở đây có ý nghĩa hơn nhiều. Trả lời cập nhật.
Stéphane Chazelas

4

Đối với các tệp lớn sử dụng sắp xếp sẽ chậm. Tôi đã viết một chương trình C ngắn để giải quyết vấn đề tương đương ( xem ý chính này cho Makefile với các bài kiểm tra ):

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

sử dụng:

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

Bạn có một bài kiểm tra? Không có ý kiến ​​trong mã. Nói chung, không nên sử dụng mã chưa được kiểm tra và xuất bản mã chưa được kiểm tra hoặc chưa được xử lý - không quan trọng cho dù đó là thông lệ. Khả năng xem xét sửa đổi cũng bị giới hạn trên nền tảng này, hãy xem xét một nền tảng lưu trữ mã rõ ràng.
Karl Richter

Các bài kiểm tra @KarlRichter là một ý tưởng tốt để thêm. Tôi tìm thấy phiên bản cũ bị sặc trên các ký tự '\ 0'. Phiên bản này sẽ hoạt động (ít nhất vượt qua một vài thử nghiệm cơ bản).
Bjoern Dahlgren

fgetsđược một dòng, không phải là một bộ đệm đầy đủ. Bạn đang quét bộ đệm đầy đủ 4096 byte cho mỗi dòng được đọc từ stdin. Bạn cần freadở đây, không fgets.
Stéphane Chazelas

@ StéphaneChazelas tuyệt vời - không biết về fread (hiếm khi làm I / O từ C). ví dụ cập nhật để sử dụng fread thay thế.
Bjoern Dahlgren

Tôi đã thêm một ifkhối xung quanh các câu lệnh printf, giúp đầu ra dễ đọc hơn nếu một số byte không xuất hiện trong tệp đầu vào: gist.github.com/martinvonwittich/ Lỗi
Martin von Wittich

3

Như thường lệ, sigma và CV thường rất quan trọng khi đánh giá dữ liệu thống kê về nội dung của tệp nhị phân, tôi đã tạo một chương trình cmdline biểu đồ tất cả dữ liệu này dưới dạng một vòng tròn sai lệch byte so với sigma.
http://wp.me/p2FmmK-96
Nó có thể được sử dụng với grep, xargs và các công cụ khác để trích xuất số liệu thống kê. nhập mô tả hình ảnh ở đây


1

Các recodechương trình có thể thực hiện điều này một cách nhanh chóng ngay cả đối với các file lớn, hoặc là thống kê tần số, hoặc cho byte hoặc cho các nhân vật của bộ ký tự khác nhau. Ví dụ: để đếm tần số 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

Thận trọng - chỉ định tệp của bạn để mã hóa lại thành đầu vào tiêu chuẩn, nếu không, nó sẽ âm thầm thay thế nó bằng tần số ký tự!

Sử dụng recode utf-8/..count-characters < fileđể coi tập tin đầu vào là utf-8. Nhiều bộ ký tự khác có sẵn và nó sẽ thất bại nếu tệp chứa bất kỳ ký tự không hợp lệ nào.


0

Điều này tương tự như odcâu trả lời của Stephane nhưng nó cho thấy giá trị ASCII của byte. Nó cũng được sắp xếp theo tần suất / số lần xuất hiện.

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

Tôi không nghĩ rằng điều này là hiệu quả vì nhiều quy trình được bắt đầu nhưng nó tốt cho các tệp đơn lẻ, đặc biệt là các tệp nhỏ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.