如何在二进制文件中收集字节出现统计信息?


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

该命令是否花费与字符所引用的命令相同的时间并不重要。

如果我将字符命令应用于二进制文件,则输出将包含不可打印字符的任意长序列的统计信息(我不寻求对此的解释)。

Answers:


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 Richter 2014年

似乎必须对整个文件进行排序有点矫kill过正,但对我来说还可以。
Michael Anderson

好点@Karl,尽管没有要求,但sort -n在这里使用更有意义。答案已更新。
斯特凡Chazelas

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

你有考试吗?代码中没有注释。通常,使用未经测试的和发布未经测试的或未经注释的代码不是一个好主意-不管这是常见的做法。在此平台上审查修订的可能性也受到限制,请考虑使用显式的代码托管平台。
Karl Richter 2015年

@KarlRichter测试是一个好主意。我发现旧版本被'\ 0'字符阻塞。此版本应该可以工作(至少通过一些基本测试)。
Bjoern Dahlgren 2015年

fgets得到一行,而不是缓冲区满。您正在为从stdin读取的每一行扫描4096字节的完整缓冲区。您不需要fread这里fgets
斯特凡Chazelas

@StéphaneChazelas很棒-不知道fread(很少从C做I / O)。更新了示例以使用fread代替。
Bjoern Dahlgren 2015年

我已经添加了if一块周围的printf语句,如果一些字节不输入文件出现,使输出更易读:gist.github.com/martinvonwittich/...
马丁·冯·Wittich

3

平均而言,在判断二进制文件内容的统计数据时,sigma和CV通常很重要。我创建了一个cmdline程序,该程序将所有这些数据绘制为字节与sigma偏差的ascii圆。
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

这类似于Stephane的od答案,但它显示了字节的ASCII值。它也按频率/发生次数排序。

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

我不认为这是有效的,因为启动了许多进程,但对单个文件(特别是小文件)来说是好的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.