mekkora fájljaid vannak?

és mekkora blokkméretet van a fájlrendszereden? (ezekről lehetne szavazás is).
egy ilyen szkript választ ad az első kérdésre.

szerk.: illetve ez a szkript ahhoz nyújtana segítséget, hogy milyen blokkmérettel rendelkező fájlrendszert használjunk.ad 1) lehet válaszolgatni a második kérdésre

- ez nálam az alapértelmezett, mert minden ömlesztve van ~ alatt. nem pakolom külön fájlrendszerre a kis és nagy fájlokat, nem tudom mikortól lenne érdemes.

ad 2) volt már róla szó, hogy kutyaütő szkriptelő, tehát hogyan lehet okosabban megírni a fenti szkriptet ?

- nálam kb 10 percig fut, gondoltam arra, hogy előbb lefuttatok egy ls -lR-t find helyett, aztán arra szűrni, illetve a kettő hatványait egy másik ciklussal léptetni, nyolcmillió if helyett.

Hozzászólások

A fileok méretét így nyerd ki, ez nagyságrendekkel gyorsabb:
find ~ -type f -printf '%s\n'

Így ugyanis nem kell minden egyes filera meghívni egy ls vagy stat parancsot.

tényleg, valamit félrenéztem késő este.
de 1:16 a futási ideje és egymagos gépen 95% körül ette a procit, 4 magoson 99% egy mag 25% az egész :)

ennyi fájlra:
File count: 116395
All file size: 426 GB
Avg file size: 3 MB

viszont jópofa, hogy egymás után írja ki a sorokat, egyfajta progress bar eye candy :)

Az alabbi egy lehetseges megoldas Perlben, az elonyei:

- nincs repetitiv kod
- a file mereteket 0-tol tetszolegesen nagy ertekekig kezeli (semmi hardcoding)
- automatikusan konvertal human-readable formatumra
- nem kell, hogy parse-olja az ls kimenetet


#! /usr/bin/perl

# Usage: command [STARTDIR]
#   if STARTDIR is omitted default to /
#
# Will print logarithmic file size distribution, total file count, total and
# avarage file size.

use 5.010;
use strict;
use warnings;
use File::Find;
use Number::Format qw( format_bytes );

my $dir = $ARGV[0] // '/';
my %fsize_log_dist;
my $fcount;
my $sum_size;

sub wanted {
  return if not -f $File::Find::name;
  my $size = ( stat(_) )[7];
  my $size_class;

  # should not take log(0)
  $size_class
    = $size
    ? int( log($size) / log(2) )
    : -1;
  ++$fsize_log_dist{$size_class};
  ++$fcount;
  $sum_size += $size;
}

find( \&wanted, $dir );

for ( sort { $a <=> $b } keys %fsize_log_dist ) {

  # print without using Number::Format::format_bytes()
  #printf "%10d B <= SIZE < %10d B: %8d\n", 2**$_, 2**( $_ + 1 ),
  #  $fsize_log_dist{$_};

  printf "%4s <= SIZE < %4s : %6d\n",
    format_bytes(
      $_ == -1
    ? 0
    : 2**$_
    ),
    format_bytes( 2**( $_ + 1 ) ),
    $fsize_log_dist{$_};

}

print  "File count : $fcount\n";
printf "Total size : %4s\n", format_bytes( $sum_size );
printf "Avg size   : %4s\n", format_bytes( $sum_size / $fcount );

__END__

update: Toroltem egy sor kommentet, amiben hulyeseg volt.

Egy kis magyarazat, hatha igy egyszerubb lesz:

Az alapotlet, hogy osztalyozzuk a file-okat a meretuk kettes alapu logaritmusanak egeszresze szerint, vagyis minden file-ra vegyuk

log2($size)

-at, ami ugyanaz mint

log($size) / log(2)

, ahol a

log()

fuggveny a termeszetes alapu logaritmus. Konkretan fogjunk egy hasht (

%fsize_log_dist

- filesize logarithmic ditribution), ahol a key az

int log2($size)

, az ertek pedig az ebbe az osztalyba tartozo file-ok szama. Kulon ugyeljunk a

$size == 0

esetre, mert veletlenul sem akarunk

log(0)

-at latni sehol sem.

Aztan az elobbieket hivatott segiteni a

File::Find

modul azzal, hogy a megadott STARTDIR-bol kiindulva, minden talalt file-ra vagy konyvtarra meghivja a

wanted()

fuggvenyt, ami a konyvtarakkal (linkekkel, socketekkel stb.) nem csinal semmit, a plain file-okra pedig azt csinalja, ami az elozo bekezdesben van. (kb. mint ez:

find STARTDIR -type f -exec wanted \;

)

Aztan a vegen a hash osszes key-ere (numerikusan rendezve oket), printelje ki szepen formazva a darabszamokat. (Apro kulonbseg a te scriptedhez kepest: ez nem fogja printelni azokat a sorokat, ahol a darabszam 0 lenne.)

Tovabbi megjegyzesek:

A

Number::Format

modul nem resze a Perl core disztribucionak, ezert hagytam ott kommentben, hogy mit erdemes printelni, ha a CPAN epp nem all rendelkezesre, hogy installald a modult.

Masreszt, ha 5.10-esnel regebbi perllel szeretned futtatni, akkor torold a

use 5.010

sort, es ird at a

my $dir = ...

sort, erre:

my $dir = defined $ARGV[0] ? $ARGV[0] : '/';

nem cpanoltam, ezért így futtattam:


  printf "%10d B <= SIZE < %10d B: %8d\n", 2**$_, 2**( $_ + 1 ),
  $fsize_log_dist{$_};

  #printf "%4s <= SIZE < %4s : %6d\n",
  # format_bytes(
  #  $_ == -1
  #? 0
  #: 2**$_
  #),
  #format_bytes( 2**( $_ + 1 ) ),
  #$fsize_log_dist{$_};

ezt volt a vége (32bites gépen):

536870912 B <= SIZE < 1073741824 B: 33
1073741824 B <= SIZE < -2147483648 B: 2
-2147483648 B <= SIZE < -1 B: 2
-1 B <= SIZE < -1 B: 2

ezt úgy látszik 64 bitesen nem csinálja:


 536870912 B <= SIZE < 1073741824 B:       70
1073741824 B <= SIZE < 2147483648 B:       11
2147483648 B <= SIZE < 4294967296 B:        9
4294967296 B <= SIZE < 8589934592 B:       40
File count : 116663
Undefined subroutine &main::format_bytes called at ./fsize.pl line 55.

real    0m4.896s
user    0m1.390s
sys     0m1.350s

közben rájöttem még az utolsó 2 kiírásban ott a cpan required hívás.
így jó:
printf "Total size : %4s\n", $sum_size ;
printf "Avg size : %4s\n", $sum_size / $fcount ;

az __END__ kell bele?

de ettől eltekintve nagyon durva, hogy az eredeti fenti shell szkript ~10 percig nyomja, ez meg 5 sec. printf %s-el 19 sec a shell is, a második meg ~1:15 ennyi fájlon.

hanem van egy érdekes dolog amit nem értek, a perl talál /-en 3 8GB-nál nagyobb fájlt:
8589934592 B <= SIZE < 17179869184 B: 3
viszont a find nem talál csak egyet (ami tail -1 előtt van az már 8589934592-nál kisebb:
sudo find / -type f -printf '%s %p\n' | sort -n | tail -1
9395245056 /proc/kcore

Itt valaszolok neked is meg mn3monicnak is, mert a valaszok nagy resze atfedne.

Szoval az elso tippem, ha mas szamu file-t talal a bashben es a perlben irt valtozat, hogy maskepp kezelik a szimbolikus linkeket. Ennek is van ket oldala:

1) Hogy kovetik-e a szimbolikus linkkent ott levo konyvtarakat, lasd

find [-P|-L|-H]

, illetve

File::Find $options{follow}

.

2) Hogy stat()-ot vagy lstat()-ot hivnak a filemeret meghatarozasahoz, az elso ugyanis a link altal mutatott file meretet fogja visszaadni, a masodik pedig maganak a linknek a meretet.

3) Sot van egy harmadik is: ha van egy konyvtarban egy adott meretu file-od, es ra ket link, akkor ezt egynek, vagy haromnak akarod szamolni?

De osszessegeben az a legegyszerubb, ha megnezitek, mi a konkret kulonbseg a ket talalati lista kozott:

1)

find /... | sort > out1.txt

2) Kommenteljetek ki a perl scriptben a normal outputot, es tegyetek valami ilyesmit a

wanted()

fuggvenybe (de ne a return ele):

print "$File::Find::name\n";

vagy

print "$File::Find::name\n" if $size >= 32*1024**2;

majd:

./fsize.pl /... | sort > out2.txt

3)

diff out[12].txt

4) Aztan lehet vizsgalni, hogy milyenek azok a file-ok, amik a diff kimeneteben szerepelnek.

A sebessegrol: a perl programnak biztosan gyorsabbnak kell lennie a bash valtozatnal, de a kulonbseg tulnyomo resze nem annak koszonheto, hogy az perlben van, hanem annak, hogy kesobb futtattad. Probald ki azt, hogy futtatsz egy elegendoen bonyolult find-ot (hogy sokaig fusson), majd rogton utana futtatod meg egyszer. Elsore hosszasan kerreg majd a winchestered, mire megtalal mindent, masodikra szinte rogton kapod majd a kimenetet. Ez azert van, mert az elso find-olasnal a szukseges adatok mind bekerultek a kerneled file cache-ebe (a memoriaba) es masodjara mar nem kell a diszket olvasni, hanem a memoriabol jonnek az adatok (es jo ideig ott is maradnak).

Az ilyen tipusu programoknal a masik fo szempont ahhoz, hogy gyorsak legyenek, hogy csak a leheto legkevesebbszer kelljen stat()-ot hivni. Ezt impliciten csinalja az ls, find stb, szoval ahanyszor hasznaljatok oket, minimum annyiszor kell vegigtekernie a diszkedet (mar ha az adatok nem maradtak benn a file cache-ben).

Aztan van (legalabb) egy elvi hiba az en perl kodomban, de azzal szerintem normal filemeretek eseten nem szabadna talalkoznotok: amikor az

int( log($size) / log(2) )

-ot szamolja, az lebegopontos aritmetikaval tortenik, es lehetseges, hogy egy-egy (2**$n vagy 2**$n-1 meretu) file a lebegopontos aritmetika hibai miatt atcsuszik a szomszedos osztalyba. Meg ha ez elo is fordul, statisztikai celokra igy is boven elegendonek kellene lennie.

Az is lehet, hogy vannak benne egyeb bugok is, de valamennyire azert teszteltem, mielott posztoltam volna, es nekem jol mukodott.

Az

__END__

nem szukseges.