İlk seviyede en fazla dosya / dizin içeren ilk 50 dizini mi buldun?


21

findEn çok sayıda dosyayı içeren bir dizin listesi oluşturmak için nasıl kullanabilirim . Listenin en yüksekten en aşağıya olmasını istiyorum. Girişin yalnızca 1 seviyeye kadar inmesini istiyorum ve genellikle bu komutu dosya sistemimin en üstünden çalıştırmam, yani /.


Farklı soru (aslında aynı, ancak farklı sorulan), ancak cevap sorunuzu da çözemez mi? unix.stackexchange.com/questions/117093/…
Patrick

Ayrıca ilgili - stackoverflow.com/questions/15216370/… . Bu benim orjinal cevabımı inode sorusuna dayandırdığım şeydir, ancak yaklaşımımın buradakilere göre bazı gelişmeler sağladığını düşünüyorum.
Graeme

@Patrick - bu sadece Graemes A'yı barındırmak için yüklü bir Q'dur. Bitlerin diğer Q'nın A'sına gömüldüğü doğrudur, ancak bu ileriye atıfta bulunabilmesi için bu parçayı ortaya çıkarmaktı.
slm

@slm Öyleyse bunun neden kopya olmadığını gerçekten anlamıyorum. Cevabı, başka bir soruya verilen cevabın bir detaylandırması gibi görünüyor. Şimdi aynı şey için 3 sorumuz var. Bağlantımdaki cevabın da daha temiz olduğunu düşünüyorum. Bulunan her dizin için bir kabuk başlatmak sadece kirli hissettiriyor.
Patrick

1
@ Patrick, GNU çözümünün her dizin için yeni bir kabuk başlatmaması için cevabı elden geçirdim. Her ne kadar bu, taşınabilir herhangi bir dosya adıyla başa çıkmak için standart bir çözümdür.
Graeme

Yanıtlar:


17

GNU araçlarını kullanma:

find / -xdev -type d -print0 |
  while IFS= read -d '' dir; do
    echo "$(find "$dir" -maxdepth 1 -print0 | grep -zc .) $dir"
  done |
  sort -rn |
  head -50

Bu iki findkomut kullanır . İlk dizinleri bulur ve bunları bir whiledöngüye yönlendirir, her dizin için bir sonraki bulguyu çalıştırır. İkincisi, tüm alt dosyaları / dizinleri birinci seviyede listeler ve grepbunları sayar. grepVerir -print0beri ikinci Bul ile kullanılmak üzere wcbir yok -zeşdeğer. Bu, yeni satırlı dosya adlarının iki kez sayılmasını engeller (kullanılmasına rağmen wchiçbir -print0fark yaratmaz).

İkinci sonuç findargümana yerleştirilir, echoböylece dizin adı aynı satıra kolayca yerleştirilebilir ( $(..)yapı otomatik olarak sonunda yeni satırı keser grep). Çizgiler daha sonra sayıya ve gösterilen en büyük 50 sayıya göre sıralanır head.

Bunun ayrıca üst noktadaki bağlama noktalarının dizinlerini içereceğini unutmayın. Bunu aşmanın basit bir yolu bir bağlama montajı kullanmak ve sonra da montaj dizinini kullanmaktır. Bunu yapmak için:

sudo mount --bind / /mnt

Daha taşınabilir bir çözüm, her dizin için farklı bir kabuk örneği kullanır ( burada da cevaplanır ):

find / -xdev -type d -exec sh -c '
  echo "$(find "$0" | grep "^$0/[^/]*$" | wc -l) $0"' {} \; |
  sort -rn |
  head -50

Örnek çıktı:

9225 /var/lib/dpkg/info
6322 /usr/share/qt4/doc/html
4927 /usr/share/man/man3
2301 /usr/share/man/man1
2097 /usr/share/doc
2097 /usr/bin
1863 /usr/lib/x86_64-linux-gnu
1679 /var/cache/apt/archives
1628 /usr/share/qt4/doc/src/images
1614 /usr/share/qt4/doc/html/images
1308 /usr/share/scilab/modules/overloading/macros
1083 /usr/src/linux-headers-3.13-1-common/include/linux
1071 /usr/src/linux-headers-3.13-1-amd64/include/config
847 /usr/include/qt4/QtGui
774 /usr/include/qt4/Qt
709 /usr/share/man/man8
616 /usr/lib
611 /usr/share/icons/oxygen/32x32/actions
608 /usr/share/icons/oxygen/22x22/actions
598 /usr/share/icons/oxygen/16x16/actions
579 /usr/share/bash-completion/completions
574 /usr/share/icons/oxygen/48x48/actions
570 /usr/share/vim/vim74/syntax
546 /usr/share/scilab/modules/m2sci/macros/sci_files
531 /usr/lib/i386-linux-gnu/wine/wine
530 /usr/lib/i386-linux-gnu/wine/wine/fakedlls
496 /etc/ssl/certs
457 /usr/share/mime/application
454 /usr/share/man/man2
450 /usr/include/qt4/QtCore
443 /usr/lib/python2.7
419 /usr/src/linux-headers-3.13-1-common/include/uapi/linux
413 /usr/share/fonts/X11/misc
413 /usr/include/linux
375 /usr/share/man/man5
374 /usr/share/lintian/overrides
372 /usr/share/cmake-2.8/Modules
370 /usr/share/fonts/X11/75dpi
370 /usr/share/fonts/X11/100dpi
356 /usr/share/icons/gnome/24x24/actions
356 /usr/share/icons/gnome/22x22/actions
356 /usr/share/icons/gnome/16x16/actions
353 /usr/share/icons/gnome/48x48/actions
353 /usr/share/icons/gnome/32x32/actions
341 /usr/lib/ghc/ghc-7.6.3
326 /usr/sbin
324 /usr/share/scilab/modules/compatibility_functions/macros
324 /usr/share/scilab/modules/cacsd/macros
320 /usr/share/terminfo/a
319 /usr/share/i18n/locales

11

GÜNCELLEME: Aşağıdakilerin hepsini yaptım, harikaydı, ama inode kullanarak dizinleri sıralamanın daha iyi bir yolunu buldum:

du --inodes -S | sort -rh | sed -n \
        '1,50{/^.\{71\}/s/^\(.\{30\}\).*\(.\{37\}\)$/\1...\2/;p}'

Ve aynı dosya sisteminde kalmak istiyorsanız, şunları yapın:

du --inodes -xS

İşte bazı örnek çıktı:

15K     /usr/share/man/man3
4.0K    /usr/lib
3.6K    /usr/bin
2.4K    /usr/share/man/man1
1.9K    /usr/share/fonts/75dpi
...
519     /usr/lib/python2.7/site-packages/bzrlib
516     /usr/include/KDE
498     /usr/include/qt/QtCore
487     /usr/lib/modules/3.13.6-2-MANJARO/build/include/config
484     /usr/src/linux-3.12.14-2-MANJARO/include/config

ŞİMDİ LS İLE:

Birkaç kişi, güncel coreutils'lere sahip olmadıklarını ve --inodes seçeneğinin kendilerine uygun olmadığını belirtti. Yani, işte:

sudo ls -AiR1U ./ | 
sed -rn '/^[./]/{h;n;};G;
    s|^ *([0-9][0-9]*)[^0-9][^/]*([~./].*):|\1:\2|p' | 
sort -t : -uk1.1,1n |
cut -d: -f2 | sort -V |
uniq -c |sort -rn | head -n10

Bu bana dukomuta hemen hemen aynı sonuçlar veriyor :

DU:

15K     /usr/share/man/man3
4.0K    /usr/lib
3.6K    /usr/bin
2.4K    /usr/share/man/man1
1.9K    /usr/share/fonts/75dpi
1.9K    /usr/share/fonts/100dpi
1.9K    /usr/share/doc/arch-wiki-markdown
1.6K    /usr/share/fonts/TTF
1.6K    /usr/share/dolphin-emu/sys/GameSettings
1.6K    /usr/share/doc/efl/html

LS:

14686   /usr/share/man/man3:
4322    /usr/lib:
3653    /usr/bin:
2457    /usr/share/man/man1:
1897    /usr/share/fonts/100dpi:
1897    /usr/share/fonts/75dpi:
1890    /usr/share/doc/arch-wiki-markdown:
1613    /usr/include:
1575    /usr/share/doc/efl/html:
1556    /usr/share/dolphin-emu/sys/GameSettings:

Bence bu includesadece programın ilk önce hangi dizine bakacağına bağlı - çünkü aynı dosyalar ve hardlinklenmişler. Yukarıdaki gibi bir şey. Yine de bu konuda yanılmış olabilir - ve düzeltme hoş geldiniz ...

Bunun altında yatan yöntem, her birinin lsdosya adlarını sed.Bundan sonra aşağıdaki dizin adını içeren dizini ile değiştirmemdir ... Kendimi biraz bulanık hissediyorum. Burada gördüğünüz gibi dosyaları doğru bir şekilde saydığına eminim:

% _ls_i ~/test
> 100 /home/mikeserv/test/realdir
>   2 /home/mikeserv/test
>   1 /home/mikeserv/test/linkdir

DU DEMO

% du --version
> du (GNU coreutils) 8.22

Bir test dizini yapın:

% mkdir ~/test ; cd ~/test
% du --inodes -S
> 1       .

Bazı çocuk dizinleri:

% mkdir ./realdir ./linkdir
% du --inodes -S
> 1       ./realdir
> 1       ./linkdir
> 1       .

Bazı dosyalar yapın:

% printf 'touch ./realdir/file%s\n' `seq 1 100` | . /dev/stdin
% du --inodes -S
> 101     ./realdir
> 1       ./linkdir
> 1       .

Bazı sabit bağlantılar:

% printf 'n="%s" ; ln ./realdir/file$n ./linkdir/link$n\n' `seq 1 100` | 
    . /dev/stdin
% du --inodes -S
> 101     ./realdir
> 1       ./linkdir
> 1       .

Hardlinklere bak:

% cd ./linkdir
% du --inodes -S
> 101

% cd ../realdir
% du --inodes -S
> 101

Yalnız sayılırlar, ama bir dizine geçin ...

% cd ..
% du --inodes -S
> 101     ./realdir
> 1       ./linkdir
> 1       .

Sonra ran betiğimi aşağıdan çalıştırdım ve:

> 100     /home/mikeserv/test/realdir
> 100     /home/mikeserv/test/linkdir
> 2       /home/mikeserv/test

Ve Graeme'nin:

> 101 ./realdir
> 101 ./linkdir
> 3 ./

Bence bu, inode saymanın tek yolunun inode olduğunu gösteriyor. Dosyaları saymak, düğümleri saymak anlamına geldiğinden, düğümleri iki kez saymazsınız - dosyaları doğru bir şekilde saymak için düğümler bir defadan fazla sayılamaz.

ESKİ:

Bunu daha hızlı buluyorum ve taşınabilir:

sh <<-\CMD
    { echo 'here='"$PWD"
        printf 'cd "${here}/%s" 2>/dev/null && {
                set -- 
                for glob in ".[!.]*" "[!.]*" ; do
                    set -- $glob "$@" && 
                        [ -e "./$1" ] || shift
                done    
                printf "%%s\\t%%s\\n" $# "$PWD"
        }\n' $( find . -depth -type d 2>/dev/null )
    } | . /dev/stdin |
    sort -rn | 
    sed -n \
        '1,50{/^.\{71\}/s/^\(.\{30\}\).*\(.\{37\}\)$/\1...\2/;p}'
CMD

-execHer dizin için olması gerekmez - yalnızca bir shell işlemini ve birini kullanır find. Ben almak zorunda set -- $globiçerecek şekilde hala hakkını .hiddendosya ve her şeyden, ama çok yakın ve çok hızlı. Sadece olurdu cdneyse içine kök dizin kontrolü için ve defol git olmalıdır.

İşte benim çıkarımın bir örneği /usr:

14684   /usr/share/man/man3
4322    /usr/lib
3650    /usr/bin
2454    /usr/share/man/man1
1897    /usr/share/fonts/75dpi
...
557     /usr/share/gtk-doc/html/gtk3
557     /usr/share/doc/elementary/latex
539     /usr/lib32/wine/fakedlls
534     /usr/lib/python2.7/site-packages/bzrlib
500     /usr/lib/python3.3/test

Ayrıca sed, en altta bulunan 50 sonucu kesmek için altta da kullanıyorum . headElbette daha hızlı olurdu, ama gerekirse her bir çizgiyi düzeltirim:

...   
159     /home/mikeserv/.config/hom...hhkdoolnlbekcfllmednbl/4.30_0/plugins
154     /home/mikeserv/.config/hom...odhpcledpamjachpmelml/1.3.11_0/js/ace
...

Kuşkusuz kaba, ama bir düşünce oldu. Başka ham aygıt I kullanımı dökmektedir 2>stderrhem findve cdiçine 2>/dev/null. Kök erişimi olmadan okuyamıyorum dizinler için izinler hataları bakmaktan daha temiz - belki de bunu belirtmeliyim find. Bu devam eden bir çalışma.

Tamam, kabuğundaki küreleri şöyle düzelttim:

for glob in ".[!.]*" "[!.]*" ; do
    set -- $glob "$@" && 
        [ -e "./$1" ] || shift
done    

Aslında bunun nasıl yapılabileceği hakkında bir soru soracağım, ama soru başlığını yazarken site , Stephane'un çoktan tartıştığı bir soru sordu . Bu yüzden uygun oldu. Görünüşe göre iyi desteklenmiş olsa da, taşınabilir değil ve Stephane'nin yorumunda orada bulduğumu buldum.[^.],!bang.

Her neyse, sadece gizli dosyaları çekmek açıkçası yeterli değildi. Bu yüzden setkelimenin tam anlamıyla konum bulmaktan kaçınmak için iki kez yapmak zorundayım $glob. Yine de performansı hiç etkilemiyor gibi görünüyor ve dizindeki her dosyayı güvenilir bir şekilde ekliyor.


@Graeme Biliyorsunuz, çözümlerimizin hiçbiri aslında inode'larla ilgilenmiyor. Listelemekte olduğumuz bu dosyaların birçoğu muhtemelen birbiriyle bağlantılı. Sanırım bunu yapabilirim ls -ive ... sanırım ... muhtemelen grep... belki - peki, hangisini kullanıyorsun -xdev,... uniqve sort?
mikeserv

Hangi sürümünü kullanıyorsun du? Benim seçeneğim duyok --inodes.
Patrick,

@Patrick - güncelleme yapmak isteyebilir - ancak gönderimi güncelledim.
mikeserv

Bu bir kanama kenarı özelliği :-) 8.21 kullanıyorum. Görünüşe göre 2013-07-27: git.savannah.gnu.org/gitweb/…
Patrick

Ayrıca, sakıncası yoksa, bunu bu soruya gönderebilir misin ? Çok taşınabilir olmadığı için kabul edeceğimi sanmıyorum, ancak çok fazla oy alacağım ve bu soruyla ilgili başka bir çözüme sahip olmak güzel olurdu.
Patrick

1

KDirStat gibi bir şey kullanmamaya rağmen Orijinalde KDE için yazılmış olsa da, GNOME'da da iyi çalışıyor ancak GUI'de dosya / dir sayısı ve ilgili kullanımın en iyi görünümünü veriyor.


1
Komut satırı yöntemini arıyorum.
slm
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.