Jak uzyskać rzeczywisty rozmiar katalogu (z du)?

17

Jak uzyskać rzeczywisty rozmiar katalogu przy użyciu standardowych narzędzi UNIX / Linux?

Alternatywne pytanie: Jak uzyskać du, aby pokazał mi rzeczywisty rozmiar katalogu (a nie użycie dysku)?

Ponieważ ludzie wydają się mieć różne definicje terminu „rozmiar”: Moja definicja „rozmiaru katalogu” jest sumą wszystkich zwykłych plików w tym katalogu.

NIE dbam o rozmiar i-węzła katalogu lub cokolwiek innego (rozmiar bloku * rozmiar bloku), które pliki zajmują w danym systemie plików. Katalog z 3 plikami, po 1 bajcie, ma rozmiar katalogu 3 bajtów (według mojej definicji).

Obliczanie rozmiaru katalogu za pomocą du wydaje się niewiarygodne.
Na przykład mkdir foo && du -b foozgłasza „4096 foo”, 4096 bajtów zamiast 0 bajtów. Przy bardzo dużych katalogach rozmiar katalogu zgłaszany przez du -hsmoże być wyłączony o 100 GB (!) I więcej (skompresowany system plików).

Więc czego (narzędzie / opcja) należy użyć, aby uzyskać rzeczywisty rozmiar katalogu?

podstawowy 6
źródło
Jaki system plików jest używany w nowej lokalizacji - czy to xfsprzypadek?
Siergiej Własow
A jeśli nowy FS to tak naprawdę XFS, znacznie zwiększone użycie dysku jest prawdopodobnie spowodowane agresywnym wstępnym przydzieleniem , co zmniejsza fragmentację plików kosztem użycia dysku.
Sergey Vlasov

Odpowiedzi:

8

Oto skrypt wyświetlający rozmiar katalogu czytelny dla człowieka przy użyciu standardowych narzędzi uniksowych (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()}'

na przykład:

$ ds ~        
72.891 GiB
jlliagre
źródło
A teraz znalazłem inną opcję którego brakuje we wszystkich proponowanych lsinwokacji tutaj: -q. Bez tej opcji skrypt ulegnie awarii, jeśli jakaś nazwa pliku zawiera znaki nowej linii. Pisanie naprawdę niezawodnych skryptów powłoki jest zbyt trudne…
Sergey Vlasov
@SergeyVlasov Skrypt, który opublikowałem, nie powinien łamać się z takimi plikami, a jedynie ignorować dodatkowe linie. Jedyny problem miałby miejsce, gdyby starannie spreparowany plik miał dodatkową linię z piątym dwukropkiem, która zawiera wartość liczbową. Twoja sugestia rzeczywiście pozwoliłaby uniknąć tej sytuacji. Dzięki za wskazówkę, skrypt zaktualizowany.
jlliagre
Doskonała odpowiedź. +1 panu
ehime
To jedno z najbardziej niezawodnych rozwiązań. Działa z nazwami plików, które zawierają spacje lub cudzysłowy, i drukuje rozmiar czytelny dla człowieka.
podstawowe6
@KIAaze Dziękujemy za sprawdzenie i naprawienie mojego kodu!
jlliagre
8

Niektóre wersje duobsługują argument, --apparent-sizeaby pokazać pozorny rozmiar zamiast użycia dysku. Zatem twoim poleceniem byłoby:

du -hs --apparent-size

Ze stron podręcznika dla du zawartych w 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
źródło
1
nie działa: zgłoś miejsce na puste reż.
Karl Forner
1
to zadziałało dla mnie.
Connorbode,
2
Daje to znacznie różne rozmiary podczas porównywania katalogów w różnych systemach plików. Na przykład ten sam folder ma pozorny rozmiar 290 GB w systemie plików ZFS i 324 GB exFat. Powyższe rozwiązania dają ten sam rozmiar.
Pixus.ru,
4

Po prostu alternatywa przy użyciu ls:

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

ls -nR: -npolub -l, ale wyświetl numeryczne identyfikatory UID i GID oraz -Rrekursywnie wyświetl podkatalogi.

grep -v:Odwróć sens dopasowania, aby wybrać niepasujące linie. (-v jest określone przez POSIX.). '^ d'wykluczy katalogi.

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

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

EDYCJA :

Edytowane jako sugestia @ Sergey Vlasov.

stderr
źródło
Korzystanie z -nopcji lszamiast zamiast -l(pokaż numery UID / GID zamiast nazw) jest bezpieczniejsze, ponieważ nazwy użytkowników i grup mogą zawierać spacje (np. Jeśli winbindlub sssdsłuży do przyłączenia systemu do domeny Windows, możesz uzyskać nazwy grup takie jak domain users) . Powinno być także szybsze, ponieważ nie trzeba wyszukiwać nazw użytkowników i grup.
Siergiej Własow
Dzięki, to O wiele szybciej niż find -exec ls!
gpothier
4

Zakładając, że masz duz GNU coreutils, to polecenie powinno obliczyć całkowity pozorny rozmiar dowolnej liczby zwykłych plików w katalogu bez żadnych arbitralnych ograniczeń liczby plików:

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

Dodaj -lopcję, dujeśli w środku są jakieś pliki dowiązane i chcesz policzyć każde dowiązanie osobno (domyślnie duzlicza wiele dowiązań tylko raz).

Najważniejszą różnicą w stosunku do zwykłego du -sbjest to, że rekurencyjne durównież liczą rozmiary katalogów, które są zgłaszane w różny sposób przez różne systemy plików; Aby tego uniknąć, findpolecenie służy do przekazywania tylko zwykłych plików du. Kolejna różnica polega na tym, że dowiązania symboliczne są ignorowane (jeśli należy je policzyć, findnależy dostosować polecenie).

Polecenie to również zużywają więcej pamięci niż zwykły du -sb, ponieważ używając --files0-from=FILEczyni duurządzenie sklepu i numer-węzła wszystkich przetwarzanych plików, w przeciwieństwie do standardowego zachowania pamiętając tylko pliki z więcej niż jednego dysku link. (Nie stanowi to problemu, jeśli -lopcja jest używana do liczenia linków twardych wiele razy, ponieważ jedynym powodem przechowywania numerów urządzeń i i-węzłów jest pomijanie plików, które zostały już przetworzone).

Jeśli chcesz uzyskać czytelną dla człowieka reprezentację całkowitego rozmiaru, po prostu dodaj -hopcję (działa to, ponieważ duwywoływany jest tylko raz i oblicza sam całkowity rozmiar, w przeciwieństwie do niektórych innych sugerowanych odpowiedzi):

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

lub (jeśli martwisz się, że niektóre efekty -bzostaną następnie zastąpione -h)

find . -type f -print0 | du -sc --apparent-size -h --files0-from=- | tail -n 1
Siergiej Własow
źródło
Nie jestem pewien, co zrobić z FreeBSD - chociaż -bprawdopodobnie można go zastąpić -A -B 1, nie ma odpowiednika --files0-from=-, a użycie xargsbędzie wymagać pewnych obejść w przypadku, gdy lista plików jest większa niż ARG_MAX(i jakieś zewnętrzne rozwiązanie dla wyjścia czytelnego dla człowieka).
Siergiej Własow
3

Jeśli wszystko, czego potrzebujesz, to rozmiar plików, z wyłączeniem miejsca zajmowanego przez katalogi, możesz zrobić coś takiego

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

@SergeyVlasov wskazał, że to się nie powiedzie, jeśli masz więcej plików niż argmax. Aby tego uniknąć, możesz użyć czegoś takiego:

find . -type f -exec du -sb '{}' \; | gawk '{k+=$1}END{print k}'
terdon
źródło
1
To polecenie po cichu da zły wynik, jeśli katalog zawiera tak wiele plików, że nie mieszczą się one w limicie wielkości argumentów execve () - w tym przypadku xargsbędą wywoływane duwiele razy, a każde wywołanie wydrukuje sumę całkowitą tylko ze swojej strony pełnej listy plików, a następnie tailpokaże całkowity rozmiar ostatniej części.
Siergiej Własow
1
@SergeyVlasov dobry punkt, nie myślałem o tym, dzięki, odpowiedź zaktualizowana.
terdon