1

I have to move the 20TB file system with a couple of million of files to a ZFS file system. So I would like to get an idea of the file sizes in order to make a good block size selection.

My current idea is to `stat --format="%s" each file and then divide the files into bins.

#!/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

The problem with this script is that I can't get find to work inside a for-loop.

Question

How to fix my script?

And is there a better way to get the all the file sizes of a file system?

4

5 回答 5

2

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

特别是因为您正在扫描许多 TB 的文件,您将需要使用支持流的东西,例如while循环:

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

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

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

于 2013-04-21T15:35:24.627 回答
1

如果只想找出介于 100M 和 1000M 之间的文件数,您可以执行以下操作

find . -size +100M -size -1000M  -type f | wc -l
于 2013-04-21T15:36:46.217 回答
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;
于 2013-04-21T16:16:19.490 回答
0

古老的du 命令将更直接地为您提供尺寸。

于 2013-04-21T21:13:35.793 回答
0

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

这可能是一个糟糕的建议,可能会导致您浪费时间。但是用 bash 爬取文件系统需要很长时间并且会消耗系统 CPU 利用率。

于 2013-04-21T15:44:19.267 回答