Temukan 50 direktori teratas yang berisi file / direktori terbanyak di level pertama?

21

Bagaimana saya dapat menggunakan finduntuk menghasilkan daftar direktori yang berisi jumlah file terbanyak. Saya ingin daftar dari tertinggi ke terendah. Saya hanya ingin daftar masuk 1 level, dan saya biasanya menjalankan perintah ini dari atas sistem file saya, yaitu /.

slm
sumber
Pertanyaan berbeda (sebenarnya sama tetapi ditanyakan berbeda), tetapi bukankah jawabannya juga akan menjawab pertanyaan Anda? unix.stackexchange.com/questions/117093/...
Patrick
Juga terkait - stackoverflow.com/questions/15216370/… . Inilah yang saya mendasari jawaban asli saya pada pertanyaan inode, meskipun saya pikir pendekatan saya menawarkan beberapa perbaikan di atas yang ada.
Graeme
@ Patrick - ini adalah Q yang dimuat hanya untuk menampung Graeme A. Benar bit dikubur di Q's lain, tapi ini adalah untuk membawa bit ini sehingga bisa direferensikan maju.
slm
@slm Maka saya benar-benar tidak mengerti mengapa ini bukan duplikat. Jawabannya sepertinya hanya uraian dari jawaban atas pertanyaan lain. Jadi sekarang kita punya 3 pertanyaan untuk hal yang sama. Saya pikir jawaban pada tautan saya juga lebih bersih. Meluncurkan shell untuk setiap direktori yang ditemukan terasa kotor.
Patrick
1
@ Patrick, saya telah mengerjakan ulang jawabannya sehingga solusi GNU tidak memulai shell baru untuk setiap direktori. Meskipun perhatikan ini adalah solusi standar untuk menangani setiap nama file dengan mudah.
Graeme

Jawaban:

17

Menggunakan alat GNU:

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

Ini menggunakan dua findperintah. Direktori menemukan pertama dan pipa mereka ke whileloop menjalankan pencarian berikutnya untuk setiap direktori. Yang kedua mencantumkan semua file anak / direktori di tingkat pertama sambil grepmenghitungnya. The grepmemungkinkan -print0untuk digunakan dengan menemukan kedua sejak wctidak memiliki -zsetara. Ini menghentikan nama file dengan baris baru yang dihitung dua kali (meskipun menggunakan wcdan tidak -print0akan membuat banyak perbedaan).

Hasil yang kedua findditempatkan dalam argumen echosehingga dan nama direktori dapat dengan mudah ditempatkan pada baris yang sama ( $(..)konstruk secara otomatis memotong baris baru di akhir grep). Baris kemudian diurutkan berdasarkan nomor dan 50 angka terbesar ditunjukkan dengan head.

Perhatikan bahwa ini juga akan mencakup direktori tingkat atas dari titik pemasangan. Cara sederhana untuk menyiasatinya adalah menggunakan bind mount dan kemudian gunakan direktori mount. Untuk melakukan ini:

sudo mount --bind / /mnt

Solusi yang lebih portabel menggunakan contoh shell yang berbeda untuk setiap direktori (juga dijawab di sini ):

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

Output sampel:

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
Graeme
sumber
11

UPDATE: Saya melakukan semua itu di bawah ini, yang keren, tapi saya menemukan cara yang lebih baik untuk menyortir direktori dengan menggunakan inode:

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

Dan jika Anda ingin tetap di sistem file yang sama Anda lakukan:

du --inodes -xS

Berikut beberapa contoh output:

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

SEKARANG DENGAN LS:

Beberapa orang mengatakan mereka tidak memiliki coreutil terbaru dan opsi --inodes tidak tersedia untuk mereka. Jadi, ini dia:

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

Ini memberikan saya hasil yang hampir sama dengan duperintah:

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:

Saya pikir includemasalahnya tergantung pada direktori mana program terlihat pada awalnya - karena mereka file yang sama dan di-hardlink. Agak suka hal di atas. Saya bisa saja salah tentang itu - dan saya menerima koreksi ...

Metode yang mendasari ini adalah bahwa saya mengganti setiap lsnama file dengan nama direktori yang berisi di sed.Mengikuti dari itu ... Yah, saya sendiri agak kabur. Saya cukup yakin itu secara akurat menghitung file, seperti yang Anda lihat di sini:

% _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

Buat direktori pengujian:

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

Beberapa direktori anak-anak:

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

Buat beberapa file:

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

Beberapa hardlink:

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

Lihatlah hardlinks:

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

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

Mereka dihitung sendiri, tetapi naik satu direktori ...

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

Kemudian saya menjalankan skrip saya dari bawah dan:

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

Dan Graeme:

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

Jadi saya pikir ini menunjukkan bahwa satu-satunya cara untuk menghitung inode adalah dengan inode. Dan karena menghitung file berarti menghitung inode, Anda tidak dapat menghitung dua kali inode - untuk menghitung file secara akurat inode tidak dapat dihitung lebih dari sekali.

TUA:

Saya menemukan ini lebih cepat, dan ini portabel:

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

Tidak harus -execuntuk setiap direktori - hanya menggunakan proses satu shel dan satu find. Saya harus set -- $globtetap benar untuk memasukkan .hiddenfile dan yang lainnya, tetapi sangat dekat dan sangat cepat. Anda akan cdmasuk ke direktori root apa saja yang harus Anda periksa dan pergilah.

Berikut ini contoh dari hasil keluaran saya /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

Saya juga menggunakan seddi bagian bawah sana untuk memotongnya ke 50 hasil teratas. headakan lebih cepat, tentu saja, tetapi saya juga memotong setiap baris jika perlu:

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

Memang kasar, memang, tapi itu hanya pemikiran. Perangkat kasar lain yang saya gunakan adalah dumping 2>stderruntuk keduanya finddan cdmasuk 2>/dev/null. Itu lebih bersih daripada melihat kesalahan izin untuk direktori yang tidak dapat saya baca tanpa akses root - mungkin saya harus menentukannya untuk find. Ya, ini masih dalam proses.

Ok, jadi saya memperbaiki gumpalan shell seperti ini:

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

Saya sebenarnya akan mengajukan pertanyaan tentang bagaimana hal itu bisa dilakukan, tetapi ketika saya mengetikkan judul pertanyaan, situs itu mengarahkan saya ke sebuah pertanyaan terkait yang disarankan di mana, lihatlah, Stephane sudah menimbang . Jadi itu nyaman. Ternyata [^.],sementara didukung dengan baik, tidak portabel dan Anda harus menggunakan !bang.saya menemukan bahwa dalam komentar Stephane di sana.

Bagaimanapun, menarik file tersembunyi saja tidak cukup, jelas. Jadi saya harus setdua kali untuk menghindari mencari posisi untuk literal $glob. Namun, tampaknya tidak mempengaruhi kinerja sama sekali, dan itu andal menambahkan setiap file dalam direktori.

mikeserv
sumber
@Graeme Anda tahu, tidak satu pun dari solusi kami yang benar-benar menangani inode. Banyak dari file yang kami cantumkan cenderung saling terkait satu sama lain. Saya pikir saya bisa melakukan ini dengan ls -idan ... Saya kira ... mungkin grep... mungkin - yah, Anda menggunakan -xdev,yang merupakan awal ... uniqdan sort?
mikeserv
Versi apa duyang Anda jalankan? Saya dutidak punya --inodespilihan.
Patrick
@ Patrick - mungkin ingin memperbarui - tapi saya memperbarui pos.
mikeserv
Itu fitur tepi berdarah :-) Saya menjalankan 8.21. Sepertinya sudah ditambahkan 2013-07-27: git.savannah.gnu.org/gitweb/…
Patrick
Juga, jika Anda tidak keberatan, bisakah Anda mempostingnya di pertanyaan ini . Saya tidak berpikir saya akan menerimanya karena ini tidak terlalu portabel, tapi saya akan merasa senang, dan akan menyenangkan untuk memiliki solusi lain pada pertanyaan.
Patrick
1

Mengapa tidak menggunakan sesuatu seperti KDirStat Meskipun pada awalnya ditulis untuk KDE tetapi berfungsi baik dengan GNOME juga Ini memberi Anda tampilan terbaik dari jumlah file / dir dan penggunaan masing-masing dalam GUI

teman teman
sumber
1
Mencari metode baris perintah.
slm