例:ファイル「mybinaryfile」があり、16進数の内容は次のとおりです。
A0 01 00 FF 77 01 77 01 A0
このファイルにあるA0バイトの数、01の数などを知る必要があります。結果は次のようになります。
A0: 2
01: 3
00: 1
FF: 1
77: 2
シェルでこれを直接カウントする方法はありますか、またはこの特定のタスクを実行するためにプログラムを任意の言語で記述する必要がありますか?
これは od を使用して1行に1つの16進値を表示し、ソートしてカウントします。
od -t x1 -w1 -v -An mybinaryfile | sort | uniq -c
(-w1
は拡張機能であり、 [〜#〜] posix [〜#〜] によって必須ではありません。)
クイックPythonソリューション:
_#!/usr/bin/env python3
import sys, itertools, collections
print(
*itertools.starmap(
"{:02X}: {:d}".format,
collections.Counter(sys.stdin.detach().read()).items()),
sep="\n")
_
一発ギャグ:
_python3 -c 'import sys, itertools, collections; print(*itertools.starmap("{:02X}: {:d}".format, collections.Counter(sys.stdin.detach().read()).items()), sep="\n")' \
< input.bin
_
出力を頻度で降順に並べ替える場合は、.items()
を .most_common()
に置き換えます。別の方法として、または他の並べ替えスキームでは、組み込みの sorted()
関数を使用するか、 sort(1)
プログラムを使用して出力を後処理します。
現在の状態では、プログラムは標準入力データ全体をバイトバッファーに投入し、比較的小さなファイルには問題ありません。大きなファイルの場合、プログラムを ファイルをチャンクで読み取る に書き換える必要があります。
< my_binary_file xxd -p | fold -w 2 | sort | uniq -c
1 00
3 01
2 77
2 a0
1 ff
< my_binary_file xxd -p | fold -w 2 | sort | uniq -c | awk '{print $2": "$1}'
00: 1
01: 3
77: 2
a0: 2
ff: 1
< my_binary_file
は、my_binary_file
の内容をxxd
コマンドの標準入力に渡します。xxd -p
は、標準入力から読み取ったデータを16進ダンプに変換し、修飾子-p
(プレーン)は、オフセットやテキスト表現なしで数字のみを出力するようにプログラムに指示します。fold -w 2
は、2文字ごとに改行文字を挿入し(-w 2
)、入力ストリームを改行で区切られたバイトリストに変換します。sort
は、名前が示すように、バイト値をグループ化して行をソートします。uniq -c
は、入力データ内の各値の出現をカウントします。awk
magicが出力形式を元の投稿で要求された形式に変換します。ファイルが非常に大きい場合は、数を増やして並べ替えることができます
od -t x1 -w1 -v -An binaryfile |
awk '{h[$1]++} END {for (v in h) {printf "%d\t%s\n", h[v], v} }' |
sort -k2
POSIXソリューションが必要な場合
od -t x1 -v -An binaryfile |
tr ' ' '\n' |
awk '$1 > "" { h[$1]++ } END { for (v in h) {printf "%d\t%s\n", h[v], v} }' |
sort -k2