$templateBlock
给定一个文件,我需要搜索与特定大小的输入块匹配的块数$blockSize
。
dd
完成这项任务的有效方法是什么?下面的方法很糟糕而且很慢,因为它调用了dd
太多次。
while [ $i -lt $totalBlocks]; do
dd if="$pathToFile" bs=$blockSize count=1 skip=$i | diff $templateBlock -
# Increase $count if $? is 0
# Increase $i by 1
done
最好的方法可能是dd
阅读$totalSize
,并且$blockSize
一次只处理所有阅读的内容。这样,我只需要调用dd
一次。换句话说,dd
一次读取所有(或许多)块,并且我可以一次处理每个块。是否有可能做到这一点?
也许是这样的:
dd if="$pathToFile" bs=$blockSize | for-each-block {
diff $templateBlock -
# Update $count if $? is 0
}
理想情况下,我只想使用 shell 实用程序。
换句话说,我宁愿不必使用 Python 或类似的程序编写程序。
答案1
在 shell 脚本中,最好使用cmp
GNU diffutils。它会为您比较数据,甚至可以跳过偏移量,--ignore-initial=SKIP1:SKIP2
以便您可以针对每个扇区偏移量运行,并且它将在找到的第一个差异处退出......这是半高效的,但如果您想运行,cmp
这仍然是很多调用cmp
它对于每个部门...
您还可以使用grep -abo
或strings -t d
来查找可能的字节偏移候选,但这取决于您正在寻找的实际模式。这样做的优点是一次程序调用即可搜索整个内容,而不是数千次调用(每个扇区一次)。
除非您碰巧找到一个恰好可以为您完成所有工作的命令行实用程序,否则您无法击败根据您的要求一次性搜索整个内容的小型 C/Go/Python 脚本...
您的脚本想法当然也有效,但它只是意味着在循环内再次调用dd
(或,或其他)以一次读取一个标准输入块,它可能比以前慢......read
答案2
您可以使用该split
命令对文件的连续块运行“过滤器”,并使用cmp
、echo
和编写过滤器true
,为每个成功的匹配获取换行符,然后用于wc
对这些匹配进行计数。例如,如果$F
是文件、$TB
模板块文件和$SZ
模板块的大小,则它可能类似于以下命令行:
$ split -b $SZ --filter="cmp $TB >& /dev/null && echo ; true" $F | wc -l
请注意,true
这可确保过滤器命令行成功,并且为了节省输入,您可以使用它:
来代替,尽管这不会提高可读性。
还要注意所有输出的重定向cmp
,即它的 stdout 和 stderr,因为只有它的返回代码是感兴趣的。