![如何使用可选偏移量找到块设备上的第一个非零字节?](https://linux22.com/image/191975/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E5%8F%AF%E9%80%89%E5%81%8F%E7%A7%BB%E9%87%8F%E6%89%BE%E5%88%B0%E5%9D%97%E8%AE%BE%E5%A4%87%E4%B8%8A%E7%9A%84%E7%AC%AC%E4%B8%80%E4%B8%AA%E9%9D%9E%E9%9B%B6%E5%AD%97%E8%8A%82%EF%BC%9F.png)
我试图使用并打印其偏移量来查找块设备上的第一个非零字节(从可选偏移量开始)dd
,但我被卡住了。我没有dd
在标题中提及,因为我认为可能有比dd
这样做更合适的工具,但我认为dd
应该是一个好的开始。如果您知道更合适的工具和/或更有效的方法来实现我的目标,那也很好。
dd
与此同时,我将向您展示到目前为止我在 bash 方面取得的进展。
#!/bin/bash
# infile is just a temporary test file for now, which will be replaced with /dev/sdb, for instance
infile=test.txt
offset=0
while true; do
byte=`dd status='none' bs=1 count=1 if="$infile" skip=$offset`
ret=$?
# the following doesn't appear to work
# ret is always 0, even when the end of file/device is reached
# how do I correctly determine if dd has reached the end of file/device?
if [ $ret -gt 0 ]; then
echo 'error, or end of file reached'
break
fi
# I don't know how to correctly determine if the byte is non-zero
# how do I determine if the read byte is non-zero?
if [ $byte ???? ]; then
echo "non-zero byte found at $offset"
break
fi
((++offset))
done
正如您所看到的,我遇到了两个不知道如何解决的问题
:当到达文件/设备末尾时如何进行while
循环?给出的退出代码为,而我期望的是非零退出代码。 b.如何评估在 stdout 上读取并返回的字节是否非零?我想我在某处读过,在 bash 中也应该特别注意字节,但我什至不确定这是否适合这种情况。break
dd
dd
0
dd
\0
您能给我一些关于如何进行的提示,或者建议和替代方法来实现我的目标吗?
答案1
您可以使用以下方法执行此操作cmp
,比较/dev/zero
:
cmp /path/to/block-device /dev/zero
cmp
将为您提供第一个非零字节的偏移量。
如果您想跳过字节,可以使用 GNUcmp
的-i
选项,或者如果您不使用 GNU cmp
,请使用以下命令为其提供适当的数据dd
:
cmp -i 100 /path/to/block-device /dev/zero
dd if=/path/to/block-device bs=1 skip=100 | cmp - /dev/zero
这适用于任何文件,而不仅仅是块设备。
答案2
斯蒂芬·基特的回答使这有点毫无意义(它更简洁,速度快一个数量级以上),但您拥有的另一种选择是(十六进制)转储设备的内容,每行一个字节,并将其通过管道传输到打印的程序其表示形式不是的第一个字节的地址,00
一旦找到它就退出:
od -Ad -w1 -tx1 /dev/device | awk '$2 && $2 != "00" { print $1 + 1; exit }'
od
的-j
选项允许您选择要跳过的字节数(在输入的开头)。
更快的变化(感谢彼得·科德斯' 评论)需要更多的输入:
od -Ad -tx1 | awk '
{
for (i=2; i<=NF; i++)
if ($i != "00") {
print ($1 + i -1)
exit
}
}'
允许od
以其首选格式输出数据需要通过将其在行中出现的位置添加到行地址来计算第一个非零字节的偏移量。