我有二进制数据,我以xxd -ps
十六进制格式查看。我注意到分隔符为 的两个标头之间的字节距离为 48300 (=805*60) 字节fafafafa
。文件的开头部分应该被跳过。
示例十六进制数据,其中标题 fafafafa 之间有 48300 字节,您可以获得这里被称为数据26.6.2015.txt其中三个标头及其几乎等效的二进制文件这里被称为test_27.6.2015.bin它只有前两个标头。在这两个文件中,最后一个头的数据都不是完整的长度;否则,您可以假设字节偏移量是固定的,即标头之间的数据长度。
算法伪代码
- 查看标题结束位置
- 查看前两个标题位置并设置这些位置的差异(d2 - d1) 事件之间的距离;该事件长度是固定的 (777)
- 按字节位置分割数据 (777) - TODO 我应该分割二进制格式还是
xxd -ps
转换后的数据?按字节位置 (777)
xxd -r
我可以通过类似方式将数据转换回二进制xxd -ps | split and store | xxd -r
,但我仍然不确定这是否有必要。
在哪个阶段可以分割二进制数据?仅采用xxd -ps
转换后的格式或二进制数据。
如果以xxd -ps
转换后的格式分割,我认为 for 循环是遍历文件的唯一方法。可能的拆分工具csplit
,split
...,不确定。然而,我不确定。
grep(ggrep 是 gnu grep)对十六进制数据的输出
$ xxd -ps r328.raw | ggrep -b -a -o -P 'fafa' | head
49393:fafa
49397:fafa
98502:fafa
98506:fafa
147611:fafa
147615:fafa
196720:fafa
196725:fafa
245830:fafa
245834:fafa
在二进制文件中执行类似的 grep 时,仅将空行作为输出。
$ ggrep -b -a -o '\xfa' r328.raw
文档
找到了给我的文档这里下图是一般 SRS 数据格式:
您可以在哪个阶段拆分二进制数据(作为二进制数据或xxd -ps
转换后的数据)?
答案1
可以对二进制文件进行操作,无需经过xxd。我通过 xxd 跑回了你的数据并用来grep -b
向我展示字节偏移量\xfa
二进制文件中的模式(从 hex 转换为 chars )。
我sed
从输出中删除了匹配的字符,只留下数字。然后,我将 shell 位置参数设置为结果偏移量 ( set --
...)
xxd -r -p <data26.6.2015.txt >/tmp/f1
set -- $(grep -b -a -o -P '\xfa\xfa\xfa\xfa' /tmp/f1 | sed 's/:.*//')
现在,您在 $1、$2、... 中有一个偏移量列表,然后您可以使用 dd 提取您感兴趣的部分,将块大小设置为 1 ( bs=1
),以便它逐字节读取。skip=
表示输入中要跳过多少字节,以及count=
要复制的字节数。
start=$1 end=$2
let count=$end-$start
dd bs=1 count=$count skip=$start </tmp/f1 >/tmp/f2
上面从第一个模式的开始到第二个模式之前提取。要不包含该模式,您可以在开始时添加 4(计数会减少 4)。
如果要提取所有部分,请使用同一代码的循环,并将起始偏移量 0 和结束偏移量文件大小添加到数字列表中:
xxd -r -p <data26.6.2015.txt >/tmp/f1
size=$(stat -c '%s' /tmp/f1)
set -- 0 $(grep -b -a -o -P '\xfa\xfa\xfa\xfa' /tmp/f1 | sed 's/:.*//') $size
i=2
while [ $# -ge 2 ]
do start=$1 end=$2
let count=$end-$start
dd bs=1 count=$count skip=$start </tmp/f1 >/tmp/f$i
let i=i+1
shift
done
如果 grep 无法处理二进制数据,您可以使用 xxd 十六进制转储数据。首先删除所有换行符以获得一大行,然后使用未转义的十六进制值执行 grep,然后将所有偏移量除以 2,并使用原始文件执行 dd:
xxd -r -p <data26.6.2015.txt >r328.raw
tr -d '\n' <data26.6.2015.txt >f1
let size2=2*$(stat -c '%s' f1)
set -- 0 $(grep -b -a -o -P 'fafafafa' f1 | sed 's/:.*//') $size2
i=2
while [ $# -ge 2 ]
do let start=$1/2
let end=$2/2
let count=$end-$start
dd bs=1 count=$count skip=$start <r328.raw >f$i
let i=i+1
shift
done
答案2
输出到伟大的meuh回答他在哪里使用数据数据26.6.2015.txt。
#1
$ cat 27.6.2015_1.sh && sh 27.6.2015_1.sh
xxd -r -p <data26.6.2015.txt >/tmp/f1
size=$(stat -c '%s' /tmp/f1)
pat=$(echo -e '\xfa\xfa\xfa\xfa')
set -- 0 $(ggrep -b -a -o "$pat" /tmp/f1 | sed 's/:.*//') $size
i=2
while [ $# -ge 2 ]
do start=$1 end=$2
let count=$end-$start
dd bs=1 count=$count skip=$start </tmp/f1 >/tmp/f$i
let i=i+1
shift
done
72900+0 records in
72900+0 records out
72900 bytes (73 kB) copied, 0.160722 s, 454 kB/s
#2
$ cat 27.6.2015_2.sh && sh 27.6.2015_2.sh
xxd -r -p <data26.6.2015.txt >/tmp/f1
size=$(stat -c '%s' /tmp/f1)
set -- 0 $(ggrep -b -a -o -P '\xfa\xfa\xfa\xfa' /tmp/f1 | sed 's/:.*//') $size
i=2
while [ $# -ge 2 ]
do start=$1 end=$2
let count=$end-$start
dd bs=1 count=$count skip=$start </tmp/f1 >/tmp/f$i
let i=i+1
shift
done
72900+0 records in
72900+0 records out
72900 bytes (73 kB) copied, 0.147935 s, 493 kB/s
#3
$ cat 27.6.2015_3.sh && sh 27.6.2015_3.sh
xxd -r -p <data26.6.2015.txt >r328.raw
tr -d '\n' <data26.6.2015.txt >f1
let size2=2*$(stat -c '%s' f1)
set -- 0 $(ggrep -b -a -o -P 'fafafafa' f1 | sed 's/:.*//') $size2
i=2
while [ $# -ge 2 ]
do let start=$1/2
let end=$2/2
let count=$end-$start
dd bs=1 count=$count skip=$start <r328.raw >f$i
let i=i+1
shift
done
24292+0 records in
24292+0 records out
24292 bytes (24 kB) copied, 0.088345 s, 275 kB/s
24152+0 records in
24152+0 records out
24152 bytes (24 kB) copied, 0.061246 s, 394 kB/s
24152+0 records in
24152+0 records out
24152 bytes (24 kB) copied, 0.058611 s, 412 kB/s
304+0 records in
304+0 records out
304 bytes (304 B) copied, 0.001239 s, 245 kB/s
输出是 1 个十六进制文件和 4 个二进制文件:
$ less f1
$ less f2
"f2" may be a binary file. See it anyway?
$ less f3
"f3" may be a binary file. See it anyway?
$ less f4
"f4" may be a binary file. See it anyway?
$ less f5
"f5" may be a binary file. See it anyway?
应该只有 3 个包含 fafafafa 的文件,因为我只在文件 data26.6.2015.txt 中给出了三个标头,其中最后一个标头的内容是存根。 f2-f5 中的输出:
$ xxd -ps f2 |head -n3
48000000fe5a1eda480000000d00030001000000cd010000010000000000
000000000000000000000000000000000000000000000100000001000000
ffffffff57ea5e5580510b0048000000fe5a1eda480000000d0003000100
$ xxd -ps f3 |head -n3
fafafafa585e0000fe5a1eda480000000d00030007000000cd0100000200
000000000000020000000000008000000000000000000000000000000000
01000000ffffffff72ea5e55b2eb0900105e000016000000010000000000
$ xxd -ps f4 |head -n3
fafafafa585e0000fe5a1eda480000000d00030007000000cd0100000300
000000000000020000000000008000000000000000000000000000000000
01000000ffffffff72ea5e55f2ef0900105e000016000000010000000000
$ xxd -ps f5 |head -n3
fafafafa585e0000fe5a1eda480000000d00030007000000cd0100000400
000000000000020000000000008000000000000000000000000000000000
01000000ffffffff72ea5e55a9f10900105e000016000000010000000000
在哪里
- f1 是整个数据文件数据26.6.2015.txt(不必包含)
- f2 是文件头,即文件的开头数据26.6.2015.txt直到第一个标题发发发发(不必包含)
- f3 是第一个标头,正确!
- f4 是第二个标头,正确!
- f5 是第三个标头,正确!
答案3
这并不难:只需查找起始字符串,命名并匹配尾部字符串即可。否则,至少尝试靠近。您实际上并不需要所有十六进制,但使用它:
fold -w2 <hexfile |
sed -e:t -e's/[[:xdigit:]]\{2\}$/\\x&/
/f[af]$/N;/\(.\)..\1$/!s/.*\n/&\\x/;t
/^.*\(.\)\(\n.*\)\n\(.*\n\).*/!bt
s//\3\3\3 H_E_A_D \1 E_N_D \2\2\2/
s/.* f//;s/a E.*//'
这将在每行获得一个十六进制字节码 - 每个前缀为 w/ \x
- 对于每个字节hexfile
除了其中字节码fa
或ff
依次出现 4 次。在这种情况下,它将得到一个H_E_A_D
或者E_N_D
相反,标记,其中H_E_A_D
字符串将替换四个字符串中的最后一个\xfa
,并且E_N_D
string 将替换四个连续字符串中的第一个\xff
- 这也应该使字节偏移量按行号保持同步。
像这样:
PIPELINE | grep -C8n _
输出:
(稍微修剪一下)
72596-\x8b 72597-\xfa 72598-\xfa 72599-\xfa 72600:H_E_A_D 72601-\x58 -- 72660-\x00 72661:E_N_D 72662-\xff 72663-\xff 72664-\xff 72665-\x72
因此,您可以将上述命令的输出传递给,例如:
fold ... | sed ... | grep -n _
...获取标头可能开始、结束的偏移列表。对于 GNU,grep
您可以使用-A
fter 开关来告诉它您希望在上下文序列中看到多少字节 - 例如,您可能想使用-A777
。您可以获取这样的输出并将其传递:
... | grep -A777 E_N_D | sed -ne's/\\/&&/p' | xargs printf %b
...为每个序列重现每个二进制字节,并且可以指定匹配号 w/ -m[num]
。