仅使用sed打印二进制匹配?

时间:2015-01-27 08:01:02

标签: regex sed character-encoding binaryfiles

让我们先来一个二进制测试文件:

echo -e '\x00\x01\x00\x0a\x00\x0f\x32\x7a\xb0\x00\x00\x01' > test.bin

hexdump -C test.bin 
# 00000000  00 01 00 0a 00 0f 32 7a  b0 00 00 01 0a           |......2z.....|
# 0000000d

现在让我们看看我是否可以匹配字节'序列0x0f 0x32 0x7a与sed

sed -n 's/\(\x0f\x32\x7a\)/\1/p' test.bin | hexdump -C
# 00000000  00 0f 32 7a b0 00 00 01  0a                       |..2z.....|
# 00000009

按预期工作 - 打印的匹配是从最后一个换行符0x0a到下一个结尾。现在,我只想打印匹配 - 首先我尝试在开始时使用.*正则表达式过滤掉:

sed -n 's/.*\(\x0f\x32\x7a\)/\1/p' test.bin | hexdump -C
# 00000000  0f 32 7a b0 00 00 01 0a                           |.2z.....|
# 00000008

有效 - 现在让我们做同样的事情,但对于尾随部分:

sed -n 's/.*\(\x0f\x32\x7a\).*/\1/p' test.bin | hexdump -C
# 00000000  0f 32 7a b0 00 00 01 0a                           |.2z.....|
# 00000008

嗯,那工作 - 只删除了标题部分 - 但是尾随部分仍在继续,即使我也使用sed终止了.*匹配模式??!

这里发生了什么 - 以及如何让sed仅在输出上打印出字节0x0f 0x32 0x7a(考虑到 hexdump {{1当打印匹配时,会添加最终换行符0x0a吗?

1 个答案:

答案 0 :(得分:4)

有趣。这是一个更简单的repro案例:

echo -en '\xff\x80' | sed -n 's/\xff.*/!/p' | hexdump -C

以上打印21 80 !\x80\x80也可以是更大的ASCII码,但不能更小:\x7F sed执行预期操作,只打印!

还要看看它的作用:

echo -en '\xff\x80' | sed -n 's/\xff./!/p' | hexdump -C

它什么都没打印。

所以问题就变成了,\x80及更高版本有什么特别之处?那么,UTF-8当然!在UTF-8中,拥有代码点集的第一位表示将有更多字节。 sed永远不会找到它们,所以它根本不会解释这个角色。

如果您想“修复”它,请告诉sed使用“旧的”C语言环境:

LC_ALL=C sed ...

然后你得到预期的输出:

echo -e '\x00\x01\x00\x0a\x00\x0f\x32\x7a\xb0\x00\x00\x01' |
  LC_ALL=C sed -n 's/.*\(\x0f\x32\x7a\).*/\1/p' |
  hexdump -C

00000000  0f 32 7a 0a                                       |.2z.|