Obtém a utilização do disco por tipo de arquivo?

1

Existe uma maneira de obter uma divisão de uma utilização de disco (ou diretório) baseada no tipo de arquivo da linha de comando?

Eu acho que eu poderia escrever um script bash para find+du com base em alguns tipos de arquivos conhecidos, mas eu prefiro não recriar a roda se houver um pacote que já existe para analisar isso.

    
por BassKozz 20.11.2011 / 22:47

1 resposta

1

Eu escrevi este utilitário que deve funcionar muito rapidamente, aqui está a saída no meu diretório home para uma execução padrão:

??? 3897697700  (717MiB)
.tgz    1550090721  (1478MiB)
.jpg    872736861   (832MiB)
.iso    804329472   (767MiB)
.pack   636183905   (606MiB)
.gch    528345920   (503MiB)
.d  384725346   (366MiB)
.i  354098997   (337MiB)
.sqlite 302110738   (288MiB)
.html   233729943   (222MiB)
.cs 209534627   (199MiB)
.dll    198655123   (189MiB)
.xml    192561101   (183MiB)
.pdf    184729508   (176MiB)
.deb    173972838   (165MiB)

Observe que a grande ??? post se deve aos muitos repositórios de origem .hg e .git que não possuem extensões.

O código padrão é imprimir os 15 maiores tipos de arquivos contribuintes, embora isso possa ser facilmente estendido.

Há um TODO no código para usar libmagic para obter os tipos de arquivos reais.

Aqui está o código:

#define _XOPEN_SOURCE 500
#include <ftw.h>
#include <cstdio>
#include <cstdlib>
#include <stdint.h>

#include <set>
#include <vector>
#include <algorithm>
#include <string>
#include <iostream>

static uintmax_t total        = 0ul;
static uintmax_t files        = 0ul;
static uintmax_t directories  = 0ul;
static uintmax_t symlinks     = 0ul;
static uintmax_t inaccessible = 0ul;
static uintmax_t blocks512    = 0ul;

struct byfiletype {
    std::string filetype;
    mutable uintmax_t total; // non-key

    bool operator<(const byfiletype& other) const { return filetype<other.filetype; }
    static bool largest_first(const byfiletype& a, const byfiletype& b) { return a.total>b.total; }
};

typedef std::set<byfiletype> sizemap;
static sizemap per_filetype;

std::string get_filetype(std::string fname) // TODO use libmagic to do file type detection?
{
    size_t pos = fname.rfind("/");
    if (std::string::npos != pos) fname = fname.substr(pos+1);

    pos = fname.rfind(".");

    return (std::string::npos != pos)
        ? fname.substr(pos)
        : "???";
}

static int
display_info(const char *fpath, const struct stat *sb,
             int tflag, struct FTW *ftwbuf)
{
    switch(tflag)
    {
        case FTW_D:
        case FTW_DP:  directories++;  break;
        case FTW_NS:
        case FTW_SL:
        case FTW_SLN: symlinks++;     break;
        case FTW_DNR: inaccessible++; break;
        case FTW_F:   
                      files++; 
                      byfiletype entry = { get_filetype(fpath), sb->st_size };
                      sizemap::iterator match = per_filetype.find(entry);

                      if (match != per_filetype.end()) 
                          match->total += sb->st_size;
                      else 
                          per_filetype.insert(entry);

                      break;
    }
    total += sb->st_size;
    blocks512 += sb->st_blocks;
    return 0; /* To tell nftw() to continue */
}

int
main(int argc, char *argv[])
{
    int flags = FTW_DEPTH | FTW_MOUNT | FTW_PHYS;

    if (nftw((argc < 2) ? "." : argv[1], display_info, 20, flags) == -1)
    {
        perror("nftw");
        exit(EXIT_FAILURE);
    }

    printf("Total size: %7jd\n", total);
    printf("In %jd files and %jd directories (%jd symlinks and %jd inaccessible directories)\n", files, directories, symlinks, inaccessible);
    printf("Size on disk %jd * 512b = %jd\n", blocks512, blocks512<<9);

    size_t N = std::min(15ul, per_filetype.size());
    typedef std::vector<byfiletype> topN_t;
    topN_t topN(N);
    std::partial_sort_copy(
            per_filetype.begin(), per_filetype.end(),
            topN.begin(), topN.end(),
            byfiletype::largest_first);

    for (topN_t::const_iterator it=topN.begin(); it!=topN.end(); ++it)
    {
        std::cout << it->filetype << "\t" << it->total << "\t(" << ((it->total)>>20) << "MiB)" << std::endl;
    }

    exit(EXIT_SUCCESS);
}
    
por sehe 20.11.2011 / 23:41