在非常大的文件系统上获取每个文件的文件大小

时间:2013-04-21 15:00:01

标签: linux bash ubuntu filesystems centos

我必须将带有数百万个文件的20TB文件系统移动到ZFS文件系统。所以我想知道文件大小,以便选择一个好的块大小。

我目前的想法是对每个文件进行`stat --format =“%s”,然后将文件分成多个文件夹。

#!/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循环中工作。

问题

如何修复我的脚本?

有没有更好的方法来获取文件系统的所有文件大小?

5 个答案:

答案 0 :(得分:2)

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

特别是因为您正在扫描多个TB级的文件,您将需要使用支持流式传输的内容,例如while循环:

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

对于可以流式传输的内容,您的脚本至少可以正常工作,但请记住,此技术会强制您为找到的每个文件调用一次外部命令(stat)。这将导致stat命令的大量进程创建,销毁和启动成本。如果你有GNU find,那么在find命令中输出每个文件大小的东西,例如-printf选项,会表现得更好。

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

答案 1 :(得分:1)

如果只想查找100M到1000M之间的文件数,可以执行以下操作

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

答案 2 :(得分:0)

我会调查使用dd来读取zfs元数据,它应该包含在数据磁盘本身中。

这可能是一个糟糕的建议,可能会导致你浪费时间。但是使用bash爬行文件系统需要很长时间并且会损坏系统cpu利用率。

答案 3 :(得分: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;

答案 4 :(得分:0)

尊敬的du command会更直接地为您提供尺码。

相关问题