2013-04-21 45 views
1

我必须将具有几百万个文件的20TB文件系统移动到ZFS文件系统。所以我想了解一下文件大小,以便选择一个好的块大小。在非常大的文件系统上获取每个文件的文件大小

我目前的想法是`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循环中工作。

问题

如何解决我的脚本?

是否有更好的方式来获得文件系统的所有文件大小?

+0

也许使用'awk' ...但我不相信你应该制作相似大小的文件箱...... – 2013-04-21 15:06:27

+0

你用上面的代码得到了什么错误? – Mat 2013-04-21 15:25:38

+0

@Mat它只是没有做任何事情。所以很难说出什么问题。 – 2013-04-21 15:38:14

回答

2

主要问题是您正在使用命令替换将find的输出提供给for循环。命令替换通过在括号(或反引号)内运行命令来完成,收集其输出并将其替换为脚本。这不支持流式传输,这意味着在完成find扫描之前,for循环不会运行,并且您还需要大量内存来缓冲find的输出。

尤其是因为您在扫描数TB的价值的文件,你将要使用的东西,支持流媒体,像while循环:

find /bin -type f | while read f; do 
    ... 
done 

的东西,能流,你的脚本将至少工作,但请记住,此技术会强制您为每个找到的文件调用一次外部命令(stat)。这会为stat命令带来很多进程创建,销毁和启动成本。例如,如果您有GNU查找,例如find命令中的每个文件的大小以及其-printf选项都会表现得更好。

另外:在循环体中的let语句看起来不对。您正在扩大$A,$B$C变量的内容,而不是引用它们。这里不应该使用$

+0

如果我在里面执行带'echo $ f'的find命令,它不会打印任何内容。就好像它不像我的那样进入循环。 – 2013-04-21 15:48:40

+0

使用'find/bin/-type f -printf'%s \ n“> /tmp/all_sizes.txt'是一个非常有趣的想法,然后对输出进行后期处理。 – 2013-04-21 16:03:43

+1

是的,您也可以使用管道对其进行流式处理,以便您不需要将中间结果存储在非常大的临时文件中。 – Celada 2013-04-21 16:14:00

1

如果只是想找出之间的文件的数量说100M和1000M你可以做以下

find . -size +100M -size -1000M -type f | wc -l 
+0

这不是一个好的解决方案,因为我需要为每个范围“统计”每个文件。不能为20TB进行缩放。 – 2013-04-21 15:40:29

+0

@SandraSchlichting实际上我认为这是一个非常好的替代解决方案。你必须用不同的'-size'参数运行这个命令9次,以便匹配你的9个桶,这意味着扫描文件系统9次,但是与shell脚本相比,每次扫描都会非常快。 – Celada 2013-04-21 15:52:46

0

我会调查用dd读ZFS元数据,这应该被包含在数据磁盘他们自己。

这可能是一个不好的建议,可能会导致你浪费时间。但是使用bash爬取文件系统将需要很长时间并且咀嚼系统CPU利用率。

+0

你能举一个例子说明一个文件是如何完成的吗? – 2013-04-21 15:52:26

+0

对不起,不。假设您有时间调查此选项,那么我会阅读ZFS白皮书和设计文档,然后开始尝试。 – Lurk21 2013-04-21 16:04:33

0
find /bin/ -type f -printf "%s\n" > /tmp/a 

然后使用以下代码作为script.pl < /tmp/a

#!/usr/bin/perl 

use warnings; 
use strict; 
use Data::Dumper; 

my %h =(); 

while (<STDIN>) { 
    chomp; 
    if ($_ <= 2**10) { $h{1} += 1} 
    elsif ($_ <= 2**11) { $h{2} += 1} 
    elsif ($_ <= 2**12) { $h{4} += 1} 
    elsif ($_ <= 2**13) { $h{8} += 1} 
    elsif ($_ <= 2**14) { $h{16} += 1} 
    elsif ($_ <= 2**15) { $h{32} += 1} 
    elsif ($_ <= 2**16) { $h{64} += 1} 
    elsif ($_ <= 2**17) { $h{128} += 1} 
    elsif ($_ > 2**17) { $h{big} += 1} 
} 

print Dumper \%h;