反转字节顺序/改变字节序的命令行

13
我正在尝试解析由Java的DataOutputStream#writeLong(...)编写的一些数据,因为Java似乎总是写big endian,所以我在使用od时遇到了问题。这是因为od始终假定endianess与当前机器的endianess匹配,而我使用的是little endian机器。
我正在寻找一个简单的一行代码来反转字节顺序。假设您知道文件的最后8个字节是由上述writeLong(...)方法编写的long型数据。我目前打印此long型数据的最佳尝试是:
tail -c 8 file | tac | od -t d8

但是tac 命令似乎只适用于文本(也合理)。我找到一些关于使用 dd conv=swab 命令的参考资料,但这只能交换成对的字节,并不能反转这8个字节。

请问有没有好的一行命令可以解决这个问题?


请提供一个示例输入/输出,并从方程式中删除Java。你想要反转每8个字节,还是所有字节? 对于所有字节:https://dev59.com/E2445IYBdhLWcg3wnroi 相似:http://unix.stackexchange.com/questions/13137/in-bash-how-to-convert-8-bytes-to-an-unsigned-int-64bit-le - Ciro Santilli OurBigBook.com
8个回答

13

您可以使用objcopy:

$ objcopy -I binary -O binary --reverse-bytes=num inputfile.bin outputfile.bin

其中num为2或4。


这样做的好处是它可以在Windows上正常工作。 - Leonardo

9

最终使用了Perl。使用了在PERL One Liners找到的一行代码:

tail -c 8 file | perl -0777e 'print scalar reverse <>' | od -t d8
0777分隔符对我来说有点令人困惑,但是这篇debian管理员的文章似乎表明它是一个“无记录分隔符”的占位符,触发完全反向逐字节。
欢迎其他建议。
编辑:在tac.c的评论中找到了另一条命令,我从GNU coreutils中下载了它:
将每个文件(如果没有给出文件或遇到“-”文件名时则为标准输入)与记录顺序相反地复制到标准输出。记录由字符串或换行符分隔。默认情况下,分隔符字符串附加到它在文件中后面的记录的末尾。
选项: -b、--before 分隔符附加到它在文件中前面的记录的开头。 -r、--regex 分隔符是一个正则表达式。 -s、--separator=separator 使用SEPARATOR作为记录分隔符。
要按字节反转文件,请使用(在bash、ksh或sh中): tac -r -s '.\| ' file

8

使用dd命令,卢克!

dd if=sourcefile of=resultfile conv=swab

3
这只适用于短(16位)而不是长(64位),对吗? - mpromonet
是的。抱歉我错过了主题的开始。 - Anton Chevychalov
我希望我能给你点赞25次。这太聪明了,太棒了,完美地解决了我的问题,而我之前并不知道dd选项的存在。而且我使用的是Mac,所以od无法进行字节序说明。太完美了。 - Ivan X
1
请注意,这仅适用于字节对,而不适用于32位字。 - Matt Montag

3

注意:GNU coreutils的下一个版本(>= 8.23)将为od命令添加--endian={little,big}选项。


由于这个问题? - Alexander Torstling

2

BASH:

od -b -v -w8 | while read pfx b8 ; do [ "$b8" ] && echo -n 12345678 | tr 87654321 \\${b8// /\\} ; done

为了更加健壮,根据 od 的输出样式可能需要压缩空格(在 w8 后面插入 "| sed 's/ */ /g'")。


2
我想到了一个Perl一行命令,可以将4字节整数从一种字节序转换为另一种字节序:
$ perl -e 'open F,shift; do { read(F,$a,4); print scalar reverse($a);} while(!eof(F));' bigend.bin > littlend.bin

这在真正的Linux机器上可能很好用,但Cygwin最终会让你吃瘪,将二进制文件视为文本并在每个0x0A字节(也称换行符)之前插入一个0x0D(又称回车符)。但是如果你使用管道到cat -,它似乎会保持不变。这对我来说很有效:

$ perl -e 'open F,shift; do { read(F,$a,4); print scalar reverse($a);} while(!eof(F));' bigend.bin | cat - > littlend.bin

我在 macOS 上找到的最佳解决方案。谢谢! - Matt Montag

1

xxd有两个标志-e-g可用于您的目的。

    -e          little-endian dump (incompatible with -ps,-i,-r).
    -g          number of octets per group in normal output. Default 2 (-e: 4).

这样,您可以进行以下操作:

tail -c 8 file | xxd -e -g8

0
一个简单的Python方法,可以反转每4个字节。使用较新的Python 3.8+海象运算符:
import sys
while word := sys.stdin.buffer.read(4):
    sys.stdout.buffer.write(bytes(reversed(word)))

以上内容很容易理解,但如果您想要更紧凑的一行代码,可以将上述脚本修改为:
python3 -c $'import sys\nwhile word := sys.stdin.buffer.read(4):\n sys.stdout.buffer.write(bytes(reversed(word)))'

请注意,$'' 表示您正在使用 bash。它允许您在 Python 命令中使用换行符。
例如,在标准输入上交换一些字符:
# echo ABCDEFGH | python3 -c $'import sys\nwhile word := sys.stdin.buffer.read(4):\n sys.stdout.buffer.write(bytes(reversed(word)))'
DCBAHGFE

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接