1

背景是我有一个日志文件,其中包含我想用 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..

我没有得到什么?

当然,我可以使用宏和其他方法来做到这一点,但我想了解为什么我的替换命令没有达到我的预期。

编辑:

对于任何想要实现相同目标的人,我提供了适用于整个文件的替换表达式。上面的表达式仅用于使用上面的日志文件示例进行测试。下面的一个是执行正确转换的那个,根据肯特在他的回答中提供的信息进行了修改。

:%s/\(\(\x\{2\} \)\{16\}\_.\)\+/\=system('xxd -p -r | xxd -g1',submatch(0))
4

1 回答 1

1

很可能,问题在于字符串转换system()输入将被vim转换为字符串,您的第一个xxd命令的输出也是如此。

您可以尝试将该十六进制部分提取到文件中。然后:

xxd -r -p theFile|vim -

然后打电话给system('xxd -g1', alltext),你会得到别的东西00

这与管道 ( xxd ...|xxd...) 的工作方式不同。但不幸的是,该system()函数不接受管道。

如果要修复:s命令,则需要systemlist()在第一次xxd调用时调用以获取二进制格式的数据,然后将其传递给 2nd xxd

:%s/\(\x\{2\} \?\)\{16\}\_.*/\=system('xxd -g1',systemlist('xxd -r -p',submatch(0)))

上面的 cmd 将生成00s. 因为没有字符串转换。

但是,当使用纯字符串以外的某些数据格式时,也许我们可以使用过滤器而不是调用system(). 这会容易得多。对于您的示例:

2,$!xxd -r -p|xxd -g1
于 2020-06-11T09:17:35.327 回答