我必须将包含几百万个文件的 20TB 文件系统移动到 ZFS 文件系统。所以我想了解文件大小,以便做出好的 block 大小选择。
我目前的想法是 `stat --format="%s"每个文件,然后将文件分成 bin。
#!/bin/bash
A=0 # nr of files <= 2^10
B=0 # nr of files <= 2^11
C=0 # nr of files <= 2^12
D=0 # nr of files <= 2^13
E=0 # nr of files <= 2^14
F=0 # nr of files <= 2^15
G=0 # nr of files <= 2^16
H=0 # nr of files <= 2^17
I=0 # nr of files > 2^17
for f in $(find /bin -type f); do
SIZE=$(stat --format="%s" $f)
if [ $SIZE -le 1024 ]; then
let $A++
elif [ $SIZE -le 2048 ]; then
let $B++
elif [ $SIZE -le 4096 ]; then
let $C++
fi
done
echo $A
echo $B
echo $C
此脚本的问题是我无法让 find
在 for 循环中工作。
问题
如何修复我的脚本?
有没有更好的方法来获取文件系统的所有文件大小?
最佳答案
主要问题是您使用命令替换将 find
的输出提供给 for
循环。命令替换通过在括号(或反引号)内运行命令完成、收集其输出并将其替换到脚本中来工作。这不支持流式传输,这意味着 for 循环在 find
扫描完全完成之前不会运行,并且您需要大量内存来缓冲 find
的输出> 也是。
特别是因为您正在扫描值(value)数 TB 的文件,所以您需要使用支持流式处理的东西,例如 while
循环:
find /bin -type f | while read f; do
...
done
对于可以流式传输的内容,您的脚本至少可以工作,但请记住,这种技术会强制您为找到的每个文件调用一次外部命令 (stat
)。这会为 stat
命令带来大量的进程创建、销毁和启动成本。如果你有 GNU find,例如在 find
命令中使用它的 -printf
选项输出每个文件的大小,性能会好得多。
旁白:循环体中的 let
语句看起来不对。您正在扩展 $A
、$B
和 $C
变量的内容,而不是引用它们。你不应该在这里使用 $
。
关于linux - 在非常大的文件系统上获取每个文件的文件大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16132514/