我正在解决一个难题,即找到了没有文件扩展名的数据文件。该file
命令表明它是一个data file (application/octet-stream)
。该hd
命令显示GNP。在最后一行。因此,如果我反转此文件,则将得到.PNG格式的文件,我在各处搜索了内容,但没有找到解决方案来解释如何反转二进制文件的内容。
我正在解决一个难题,即找到了没有文件扩展名的数据文件。该file
命令表明它是一个data file (application/octet-stream)
。该hd
命令显示GNP。在最后一行。因此,如果我反转此文件,则将得到.PNG格式的文件,我在各处搜索了内容,但没有找到解决方案来解释如何反转二进制文件的内容。
Answers:
使用xxd
(来自vim
)和tac
(也来自GNU coreutils,tail -r
在某些系统上):
< file.gnp xxd -p -c1 | tac | xxd -p -r > file.png
在zsh
(唯一可以在内部处理二进制数据的外壳程序中(除非您要考虑ksh93的base64编码方法)):
zmodload zsh/mapfile
(LC_ALL=C; printf %s ${(s::Oa)mapfile[file.gnp]} > file.png)
LC_ALL=C
:字符为字节$mapfile[file.gnp]
:file.gnp
文件内容s::
:将字符串拆分为其字节组成部分Oa
:O
在a
rray下标该数组上的反向rderzsh
不是唯一可以处理二进制数据的外壳。
这是使用反转二进制文件的一种方法ksh93
。我留下了代码“ loose”,以使其更易于理解。
#!/bin/ksh93
typeset -b byte
redirect 3< image.gpj || exit 1
eof=$(3<#((EOF)))
read -r -u 3 -N 1 byte
printf "%B" byte > image.jpg
3<#((CUR - 1))
while (( $(3<#) > 0 ))
do
read -r -u 3 -N 1 byte
printf "%B" byte >> image.jpg
3<#((CUR - 2))
done
read -r -u 3 -N 1 byte
printf "%B" byte >> image.jpg
redirect 3<&- || echo 'cannot close FD 3'
exit 0
read
上面的第一个文件不应读取,因为它在文件末尾已完成。
strace
并且ksh93
看起来表现很怪异,它在文件中的所有位置进行查找,并在那时读取大量内容。也许一个变种github.com/att/ast/issues/15
strace
使用脚本来了解我的意思。ksh93
读取文件数千次。例如,在读取第一个字节之前,它将在文件末尾查找64KiB,然后读取64KiB,然后在最后一个字节之前进行查找,然后读取1个字节,并对每个字节执行类似的操作。请注意,使用那些base64编码的字符串所能做的是有限的,因此,如果一次读取多个字节,提取该字节的单个字节将更加困难。
使用perl:
perl -0777pe '$_=reverse $_' [input_file]
性能测试:
dd if=/dev/urandom of=/tmp/a bs=1M count=1
LC_ALL=C tac -rs $'.\\|\n' /tmp/a > /tmp/r
time perl -0777pe '$_=reverse $_' /tmp/a | diff -q - /tmp/r
time xxd -p -c1 /tmp/a | tac | xxd -p -r | diff -q - /tmp/r
time perl -0777 -F -ape '$_=reverse@F' /tmp/a | diff -q - /tmp/r
time LC_ALL=C tac -rs $'.\\|\n' /tmp/a | diff -q - /tmp/r
结果:
perl -0777 -F
最慢。xxd
最慢。注意:diff
所有解决方案的时间运行都应该相同,因为输出应该相同。
perl
一个。我当时还没有意识到reverse
也可以反转字符串,所以这样做拆分没有太大意义,而您的版本要好得多。
我尝试了以下方法:
tac -rs '.' input.gnp > output.png
这个想法是使用任何字符作为分隔符来强制'tac'。我在一个二进制文件上尝试了它,它似乎可以工作,但是任何确认将不胜感激。
主要优点是它不会将文件加载到内存中。
tac
当输入包含换行符时,对我不起作用(在这里与GNU 8.28一起使用)。printf '1\n2' | tac -rs . | od -vAn -tc
输出\n 2 1
代替2 \n 1
。您还需要LC_ALL=C
或.
可以匹配多字节字符。
LC_ALL=C tac -rs $'.\\|\n'
似乎工作。