让我们首先有一个二进制测试文件:
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
sed
在打印匹配时将添加最终换行符 0x0a)?
最佳答案
有趣。这是一个更简单的重现案例:
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.|
关于regex - 仅使用 sed 打印二进制匹配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28165705/