Como obter o tamanho real do diretório (fora do du)?

17

Como obtenho o tamanho real do diretório, usando as ferramentas padrão UNIX / Linux?

Pergunta alternativa: Como obtenho du para me mostrar o tamanho real do diretório (não o uso do disco)?

Como as pessoas parecem ter definições diferentes do termo "tamanho": Minha definição de "tamanho do diretório" é a soma de todos os arquivos regulares nesse diretório.

NÃO me importo com o tamanho do inode do diretório ou com o que (arquivos * tamanho do bloco) os arquivos ocupam no respectivo sistema de arquivos. Um diretório com 3 arquivos, 1 byte cada, tem um tamanho de diretório de 3 bytes (por minha definição).

Calcular o tamanho do diretório usando du parece não confiável.
Por exemplo, mkdir foo && du -b foorelata "4096 foo", 4096 bytes em vez de 0 bytes. Com diretórios muito grandes, o tamanho do diretório relatado por du -hspode ser desativado em 100 GB (!) E mais (sistema de arquivos compactados).

Então, o que (ferramenta / opção) deve ser usado para obter o tamanho real do diretório?

basic6
fonte
Qual sistema de arquivos é usado no novo local - é xfspor acaso?
Sergey Vlasov
E se o seu novo FS for realmente XFS, o aumento considerável do uso do disco provavelmente se deve à pré-alocação agressiva , que diminui a fragmentação do arquivo ao custo do uso do disco.
Sergey Vlasov

Respostas:

8

Aqui está um script exibindo um tamanho de diretório legível por humanos usando as ferramentas padrão do Unix (POSIX).

#!/bin/sh
find ${1:-.} -type f -exec ls -lnq {} \+ | awk '
BEGIN {sum=0} # initialization for clarity and safety
function pp() {
  u="+Ki+Mi+Gi+Ti+Pi+Ei";
  split(u,unit,"+");
  v=sum;
  for(i=1;i<7;i++) {
    if(v<1024) break;
    v/=1024;
  }
  printf("%.3f %sB\n", v, unit[i]);
}
{sum+=$5}
END{pp()}'

por exemplo:

$ ds ~        
72.891 GiB
jlliagre
fonte
E agora eu encontrei outra opção que está faltando em todas as sugeridas lsinvocações aqui: -q. Sem essa opção, o script será interrompido se algum nome de arquivo contiver caracteres de nova linha. Escrevendo scripts shell realmente confiáveis é muito difícil ...
Sergey Vlasov
@SergeyVlasov O script que eu postei não deve quebrar com esses arquivos, apenas ignorando as linhas extras. O único caso de problema ocorreria se um arquivo cuidadosamente criado tivesse uma linha extra com um quinto cólon que contenha um valor numérico. Sua sugestão iria de fato evitar essa situação. Obrigado pela dica, script atualizado.
Jlliagre
Excelente resposta. +1 para você senhor
ehime
Esta é uma das soluções mais confiáveis. Ele funciona com nomes de arquivos que possuem espaços ou aspas e imprime um tamanho legível por humanos.
basic6
@KIAaze Obrigado por revisar e corrigir meu código!
jlliagre
8

Algumas versões dusuportam o argumento --apparent-sizepara mostrar o tamanho aparente em vez do uso do disco. Portanto, seu comando seria:

du -hs --apparent-size

Nas páginas de manual do du incluído no Ubuntu 12.04 LTS:

--apparent-size
      print apparent sizes,  rather  than  disk  usage;  although  the
      apparent  size is usually smaller, it may be larger due to holes
      in (`sparse') files, internal  fragmentation,  indirect  blocks,
      and the like
Brian
fonte
11
não trabalho: denunciar algum espaço para diretórios vazios
Karl Forner
11
isso funcionou para mim.
connorbode
2
Ele fornece tamanhos significativamente diferentes ao comparar diretórios em diferentes sistemas de arquivos. Por exemplo, a mesma pasta tem tamanho aparente de 290 GB no sistema de arquivos zfs e 324 GB de exFat. As soluções acima dão o mesmo tamanho.
Pixus.ru 16/09/16
4

Apenas uma alternativa, usando ls:

ls -nR | grep -v '^d' | awk '{total += $5} END {print total, "Total"}'

ls -nR: -nlike -l, mas liste UIDs e GIDs numéricos e -Rliste subdiretórios recursivamente.

grep -v:Inverta a sensação de correspondência, para selecionar linhas não correspondentes. (-v é especificado por POSIX.). '^ d'excluirá os diretórios.

Comando Ls: http://linux.about.com/od/commands/l/blcmdl1_ls.htm

Man Grep: http://linux.die.net/man/1/grep

EDIT :

Editado como a sugestão @ Sergey Vlasov.

stderr
fonte
Usar a -nopção em lsvez de -l(mostrar números UID / GID em vez de nomes) é mais seguro, porque os nomes de usuários e grupos podem conter espaços (por exemplo, se winbindou sssdsão usados ​​para associar o sistema a um domínio do Windows, você pode obter nomes de grupos como domain users) . Também deve ser mais rápido devido à não necessidade de pesquisar nomes de usuários e grupos.
Sergey Vlasov
Obrigado, isso é MUITO mais rápido que o find -exec ls!
gpothier
4

Supondo que você tenha dudo GNU coreutils, esse comando deve calcular o tamanho aparente total do número arbitrário de arquivos regulares dentro de um diretório sem limites arbitrários no número de arquivos:

find . -type f -print0 | du -scb --files0-from=- | tail -n 1

Adicione a -lopção a duse houver alguns arquivos com link interno e você deseja contar cada link separadamente (por padrão, duconta vários links somente uma vez).

A diferença mais importante com plain du -sbé que recursive dutambém conta tamanhos de diretórios, que são relatados de maneira diferente por diferentes sistemas de arquivos; para evitar isso, o findcomando é usado para passar somente arquivos regulares para du. Outra diferença é que os links simbólicos são ignorados (se eles devem ser contados, o findcomando deve ser ajustado).

Esse comando também consome mais memória do que o comum du -sb, porque o uso do dispositivo de armazenamento de --files0-from=FILEmarcas due números de inode de todos os arquivos processados, em oposição ao comportamento padrão de lembrar apenas arquivos com mais de um link físico. (Isso não é um problema se a -lopção for usada para contar links físicos várias vezes, porque o único motivo para armazenar números de dispositivo e inode é ignorar arquivos com link físico que já foram processados.)

Se você deseja obter uma representação legível do tamanho total, basta adicionar o -hopção (Isso funciona porque dué invocado apenas uma vez e calcula o próprio tamanho total, ao contrário de algumas outras respostas sugeridas):

find . -type f -print0 | du -scbh --files0-from=- | tail -n 1

ou (se você estiver preocupado com a -bsubstituição de alguns efeitos -h)

find . -type f -print0 | du -sc --apparent-size -h --files0-from=- | tail -n 1
Sergey Vlasov
fonte
Não sei o que fazer para o FreeBSD - embora -bprovavelmente possa ser substituído por -A -B 1, não há equivalente para --files0-from=-, e o uso xargsprecisará de algumas soluções alternativas caso a lista de arquivos seja maior que ARG_MAX(e alguma solução externa para saída legível por humanos).
Sergey Vlasov
3

Se tudo o que você deseja é o tamanho dos arquivos, excluindo o espaço que os diretórios ocupam, você pode fazer algo como

find . -type f -print0 | xargs -0 du -scb | tail -n 1

@SergeyVlasov apontou que isso irá falhar se você tiver mais arquivos do que argmax. Para evitar que você possa usar algo como:

find . -type f -exec du -sb '{}' \; | gawk '{k+=$1}END{print k}'
Terdon
fonte
11
Este comando silenciosamente fornecerá um resultado errado se o diretório contiver tantos arquivos que eles não cabem no limite do tamanho dos argumentos execve () - nesse caso, ele xargsserá chamado duvárias vezes e cada chamada imprimirá o total geral apenas por sua parte da lista completa de arquivos, tailmostrará apenas o tamanho total da última parte.
Sergey Vlasov
11
@SergeyVlasov bom ponto, eu não tinha pensado nisso, obrigado, resposta atualizada.
terdon