Vim: 用系统命令替换调用xxd导致转换错误
Vim: calling xxd with system command in substitution results in conversion error
背景是我有一个包含十六进制转储的日志文件,我想用 xxd 转换它以获得漂亮的 ASCII 列,该列显示二进制数据中可能的字符串。
日志文件格式如下:
My interesting hex dump:
00 53 00 6f 00 6d 00 65 00 20 00 74 00 65 00 78
00 74 00 20 00 65 00 78 00 61 00 6d 00 70 00 6c
00 65 00 20 00 75 00 73 00 69 00 6e 00 67 00 20
00 55 00 54 00 46 00 2d 00 31 00 36 00 20 00 69
00 6e 00 20 00 6f 00 72 00 64 00 65 00 72 00 20
00 74 00 6f 00 20 00 67 00 65 00 74 00 20 00 30
00 78 00 30 00 30 00 20 00 62 00 79 00 74 00 65
00 73 00 2e
目视选择十六进制转储并执行 xxd -r -p
然后在结果上执行 xxd -g1
正是我想要的。
但是,由于我要转换的转储数量很多,所以我宁愿自动化该过程。
所以我使用以下替代命令进行转换:
:%s/\(\x\{2\} \?\)\{16\}\_.*/\=system('xxd -g1',system('xxd -r -p',submatch(0)))
表达式匹配日志文件中的整个十六进制转储。匹配作为标准输入发送到 xxd -r -p
,其输出用作 xxd -g1
的标准输入。
好吧,至少是这样。
上面的几乎有效。它产生以下结果:
My interesting hex dump:
00000000: 01 53 01 6f 01 6d 01 65 01 20 01 74 01 65 01 78 .S.o.m.e. .t.e.x
00000010: 01 74 01 20 01 65 01 78 01 61 01 6d 01 70 01 6c .t. .e.x.a.m.p.l
00000020: 01 65 01 20 01 75 01 73 01 69 01 6e 01 67 01 20 .e. .u.s.i.n.g.
00000030: 01 55 01 54 01 46 01 2d 01 31 01 36 01 20 01 69 .U.T.F.-.1.6. .i
00000040: 01 6e 01 20 01 6f 01 72 01 64 01 65 01 72 01 20 .n. .o.r.d.e.r.
00000050: 01 74 01 6f 01 20 01 67 01 65 01 74 01 20 01 30 .t.o. .g.e.t. .0
00000060: 01 78 01 30 01 30 01 20 01 62 01 79 01 74 01 65 .x.0.0. .b.y.t.e
00000070: 01 73 01 2e .s..
所有 00
个字节神秘地转变为 01
。
它应该产生以下内容:
My interesting hex dump:
00000000: 00 53 00 6f 00 6d 00 65 00 20 00 74 00 65 00 78 .S.o.m.e. .t.e.x
00000010: 00 74 00 20 00 65 00 78 00 61 00 6d 00 70 00 6c .t. .e.x.a.m.p.l
00000020: 00 65 00 20 00 75 00 73 00 69 00 6e 00 67 00 20 .e. .u.s.i.n.g.
00000030: 00 55 00 54 00 46 00 2d 00 31 00 36 00 20 00 69 .U.T.F.-.1.6. .i
00000040: 00 6e 00 20 00 6f 00 72 00 64 00 65 00 72 00 20 .n. .o.r.d.e.r.
00000050: 00 74 00 6f 00 20 00 67 00 65 00 74 00 20 00 30 .t.o. .g.e.t. .0
00000060: 00 78 00 30 00 30 00 20 00 62 00 79 00 74 00 65 .x.0.0. .b.y.t.e
00000070: 00 73 00 2e .s..
我没有得到什么?
当然我可以使用宏和其他方法来执行此操作,但我想了解为什么我的替换命令没有达到我的预期。
编辑:
对于任何想要实现相同目的的人,我提供了适用于整个文件的替换表达式。上面的表达式仅用于测试目的,使用上面的日志文件示例。
下面的那个是执行正确转换的那个,根据 Kent 在他的回答中提供的信息修改。
:%s/\(\(\x\{2\} \)\{16\}\_.\)\+/\=system('xxd -p -r | xxd -g1',submatch(0))
很可能,问题是 system()
中的字符串转换 输入将被 vim 转换为字符串,您的第一个 xxd 命令的输出也是如此。
您可以尝试将十六进制部分提取到文件中。然后:
xxd -r -p theFile|vim -
然后调用 system('xxd -g1', alltext)
,你也会得到 00
以外的东西。
这与管道 (xxd ...|xxd...
) 的工作方式不同。但不幸的是,system()
函数不接受管道。
如果你想修复你的 :s
命令,你需要在第一次 xxd
调用时调用 systemlist()
以获取二进制格式的数据,然后将其传递给第二个xxd
:
:%s/\(\x\{2\} \?\)\{16\}\_.*/\=system('xxd -g1',systemlist('xxd -r -p',submatch(0)))
上面的 cmd 将生成 00
s。因为没有字符串转换。
然而,当处理纯字符串以外的某些数据格式时,也许我们可以使用过滤器而不是调用 system()
。会轻松很多。例如:
2,$!xxd -r -p|xxd -g1
背景是我有一个包含十六进制转储的日志文件,我想用 xxd 转换它以获得漂亮的 ASCII 列,该列显示二进制数据中可能的字符串。
日志文件格式如下:
My interesting hex dump:
00 53 00 6f 00 6d 00 65 00 20 00 74 00 65 00 78
00 74 00 20 00 65 00 78 00 61 00 6d 00 70 00 6c
00 65 00 20 00 75 00 73 00 69 00 6e 00 67 00 20
00 55 00 54 00 46 00 2d 00 31 00 36 00 20 00 69
00 6e 00 20 00 6f 00 72 00 64 00 65 00 72 00 20
00 74 00 6f 00 20 00 67 00 65 00 74 00 20 00 30
00 78 00 30 00 30 00 20 00 62 00 79 00 74 00 65
00 73 00 2e
目视选择十六进制转储并执行 xxd -r -p
然后在结果上执行 xxd -g1
正是我想要的。
但是,由于我要转换的转储数量很多,所以我宁愿自动化该过程。
所以我使用以下替代命令进行转换:
:%s/\(\x\{2\} \?\)\{16\}\_.*/\=system('xxd -g1',system('xxd -r -p',submatch(0)))
表达式匹配日志文件中的整个十六进制转储。匹配作为标准输入发送到 xxd -r -p
,其输出用作 xxd -g1
的标准输入。
好吧,至少是这样。
上面的几乎有效。它产生以下结果:
My interesting hex dump:
00000000: 01 53 01 6f 01 6d 01 65 01 20 01 74 01 65 01 78 .S.o.m.e. .t.e.x
00000010: 01 74 01 20 01 65 01 78 01 61 01 6d 01 70 01 6c .t. .e.x.a.m.p.l
00000020: 01 65 01 20 01 75 01 73 01 69 01 6e 01 67 01 20 .e. .u.s.i.n.g.
00000030: 01 55 01 54 01 46 01 2d 01 31 01 36 01 20 01 69 .U.T.F.-.1.6. .i
00000040: 01 6e 01 20 01 6f 01 72 01 64 01 65 01 72 01 20 .n. .o.r.d.e.r.
00000050: 01 74 01 6f 01 20 01 67 01 65 01 74 01 20 01 30 .t.o. .g.e.t. .0
00000060: 01 78 01 30 01 30 01 20 01 62 01 79 01 74 01 65 .x.0.0. .b.y.t.e
00000070: 01 73 01 2e .s..
所有 00
个字节神秘地转变为 01
。
它应该产生以下内容:
My interesting hex dump:
00000000: 00 53 00 6f 00 6d 00 65 00 20 00 74 00 65 00 78 .S.o.m.e. .t.e.x
00000010: 00 74 00 20 00 65 00 78 00 61 00 6d 00 70 00 6c .t. .e.x.a.m.p.l
00000020: 00 65 00 20 00 75 00 73 00 69 00 6e 00 67 00 20 .e. .u.s.i.n.g.
00000030: 00 55 00 54 00 46 00 2d 00 31 00 36 00 20 00 69 .U.T.F.-.1.6. .i
00000040: 00 6e 00 20 00 6f 00 72 00 64 00 65 00 72 00 20 .n. .o.r.d.e.r.
00000050: 00 74 00 6f 00 20 00 67 00 65 00 74 00 20 00 30 .t.o. .g.e.t. .0
00000060: 00 78 00 30 00 30 00 20 00 62 00 79 00 74 00 65 .x.0.0. .b.y.t.e
00000070: 00 73 00 2e .s..
我没有得到什么?
当然我可以使用宏和其他方法来执行此操作,但我想了解为什么我的替换命令没有达到我的预期。
编辑:
对于任何想要实现相同目的的人,我提供了适用于整个文件的替换表达式。上面的表达式仅用于测试目的,使用上面的日志文件示例。 下面的那个是执行正确转换的那个,根据 Kent 在他的回答中提供的信息修改。
:%s/\(\(\x\{2\} \)\{16\}\_.\)\+/\=system('xxd -p -r | xxd -g1',submatch(0))
很可能,问题是 system()
中的字符串转换 输入将被 vim 转换为字符串,您的第一个 xxd 命令的输出也是如此。
您可以尝试将十六进制部分提取到文件中。然后:
xxd -r -p theFile|vim -
然后调用 system('xxd -g1', alltext)
,你也会得到 00
以外的东西。
这与管道 (xxd ...|xxd...
) 的工作方式不同。但不幸的是,system()
函数不接受管道。
如果你想修复你的 :s
命令,你需要在第一次 xxd
调用时调用 systemlist()
以获取二进制格式的数据,然后将其传递给第二个xxd
:
:%s/\(\x\{2\} \?\)\{16\}\_.*/\=system('xxd -g1',systemlist('xxd -r -p',submatch(0)))
上面的 cmd 将生成 00
s。因为没有字符串转换。
然而,当处理纯字符串以外的某些数据格式时,也许我们可以使用过滤器而不是调用 system()
。会轻松很多。例如:
2,$!xxd -r -p|xxd -g1