让我们先来一个二进制测试文件:
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(考虑到 {{1当打印匹配时,会添加最终换行符0x0a吗?hexdump
答案 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.|