2013-04-21 60 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;