ค้นหาไดเรกทอรี 50 อันดับแรกที่มีไฟล์ / ไดเรกทอรีมากที่สุดในระดับแรกหรือไม่


21

ฉันfindจะใช้เพื่อสร้างรายการไดเรกทอรีที่มีจำนวนไฟล์มากที่สุดได้อย่างไร ฉันต้องการรายชื่อจากจากมากไปน้อย ฉันเพียงต้องการเช่นรายการที่จะไป 1 /ระดับลึกและฉันมักจะใช้คำสั่งนี้จากด้านบนของระบบแฟ้มของฉันคือ


คำถามที่แตกต่าง (จริง ๆ แล้วเหมือนกัน แต่ถามแตกต่างกัน) แต่คำตอบจะไม่แก้คำถามของคุณด้วยหรือไม่ unix.stackexchange.com/questions/117093/…
Patrick

นอกจากนี้ยังเกี่ยวข้อง - stackoverflow.com/questions/15216370/... นี่คือสิ่งที่ฉันใช้คำตอบดั้งเดิมของฉันจากคำถาม inode ถึงแม้ว่าฉันคิดว่าวิธีการของฉันมีการปรับปรุงบางอย่างมากกว่าที่นั่น
แกรม

@ แพทริก - นี่คือคิวที่โหลดเพียงเพื่อบ้าน Graemes A. จริงบิตถูกฝังอยู่ในอื่น ๆ ของคิว แต่นี่คือการนำบิตนี้ออกเพื่อที่จะสามารถอ้างอิงไปข้างหน้า
slm

@slm แล้วฉันไม่เข้าใจว่าทำไมสิ่งนี้จึงไม่ซ้ำกัน คำตอบของเขาดูเหมือนจะเป็นเพียงคำอธิบายรายละเอียดของคำถามอื่น ดังนั้นตอนนี้เรามี 3 คำถามสำหรับสิ่งเดียวกัน ฉันคิดว่าคำตอบในลิงค์ของฉันก็สะอาดเช่นกัน การเปิดตัวเชลล์สำหรับทุก ๆ ไดเรกทอรีพบว่ารู้สึกสกปรก
Patrick

1
@ แพทริกฉันได้ทำคำตอบใหม่เพื่อที่ว่าโซลูชัน GNU จะไม่เริ่มเชลล์ใหม่สำหรับทุกไดเรกทอรี แม้ว่าจะทราบว่านี่เป็นโซลูชันมาตรฐานในการจัดการกับชื่อไฟล์ใด ๆ
แกรม

คำตอบ:


17

การใช้เครื่องมือ 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

สิ่งนี้ใช้สองfindคำสั่ง อันดับแรกจะค้นหาไดเรกทอรีและไพพ์ไปยังwhileลูปเพื่อรันการค้นหาถัดไปสำหรับแต่ละไดเร็กทอรี รายการที่สองแสดงรายการไฟล์ / ไดเร็กทอรีทั้งหมดในระดับแรกขณะที่grepนับมัน grepช่วยให้-print0เพื่อนำไปใช้กับการค้นหาสองตั้งแต่wcยังไม่ได้-zเทียบเท่า สิ่งนี้จะหยุดชื่อไฟล์ด้วยการขึ้นบรรทัดใหม่จากการนับสองครั้ง (แม้ว่าการใช้wcและ-print0จะไม่สร้างความแตกต่างมากนัก)

ผลมาจากการที่สองfindจะอยู่ในการโต้แย้งการechoเพื่อให้มันและชื่อไดเรกทอรีสามารถถูกวางไว้บนบรรทัดเดียวกัน (คน$(..)สร้างโดยอัตโนมัติจดจ้องขึ้นบรรทัดใหม่ในตอนท้ายของgrep) เส้นจะเรียงแล้วจากจำนวนและหมายเลข 50 headที่ใหญ่ที่สุดแสดงด้วย

โปรดทราบว่าสิ่งนี้จะรวมไดเรกทอรีระดับบนสุดของจุดเชื่อมต่อด้วย วิธีง่ายๆในการหลีกเลี่ยงสิ่งนี้คือใช้ bind mount แล้วใช้ไดเร็กตอรี่ของ mount เพื่อทำสิ่งนี้:

sudo mount --bind / /mnt

โซลูชันแบบพกพาที่มากกว่านั้นใช้เชลล์อินสแตนซ์ที่แตกต่างกันสำหรับแต่ละไดเรกทอรี (ตอบด้วยที่นี่ ):

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

ตัวอย่างผลลัพธ์:

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

UPDATE: ฉันทำทั้งหมดข้างล่างซึ่งเจ๋ง แต่ฉันคิดวิธีเรียงลำดับไดเรกทอรีที่ดีกว่าโดยใช้ inode:

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

และถ้าคุณต้องการอยู่ในระบบไฟล์เดียวกับคุณ:

du --inodes -xS

นี่คือตัวอย่างผลลัพธ์:

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

ตอนนี้ด้วย LS:

มีหลายคนที่กล่าวถึงว่าพวกเขาไม่มี coreutils ที่ทันสมัยและตัวเลือก --inode ไม่สามารถใช้ได้ ดังนั้นนี่คือ ls:

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

นี่คือการให้ผลลัพธ์ที่เหมือนกันกับduคำสั่ง:

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:

ฉันคิดว่าincludeสิ่งที่ขึ้นอยู่กับไดเรกทอรีที่โปรแกรมดูครั้งแรก - เพราะพวกเขาเป็นไฟล์เดียวกันและฮาร์ดลิงก์ ค่อนข้างชอบสิ่งเหนือ ฉันอาจจะผิดเกี่ยวกับเรื่องนั้น - และฉันยินดีต้อนรับการแก้ไข ...

วิธีการพื้นฐานของสิ่งนี้คือฉันจะแทนที่lsชื่อไฟล์ของทุกคนด้วยชื่อไดเรกทอรีที่มีอยู่ในการsed.ติดตามจากนั้น ... ดีฉันเป็นคนคลุมเครือเล็กน้อย ฉันค่อนข้างแน่ใจว่ามันนับไฟล์อย่างถูกต้องอย่างที่คุณเห็นที่นี่:

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

ทำไดเรกทอรีทดสอบ:

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

บางไดเรกทอรีลูก:

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

สร้างไฟล์บางไฟล์:

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

บางส่วนของการเชื่อมโยง:

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

ดูการเชื่อมโยง:

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

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

พวกเขาถูกนับคนเดียว แต่ไปหนึ่งไดเรกทอรีขึ้นไป ...

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

จากนั้นฉันก็เรียกใช้สคริปต์การวิ่งของฉันจากด้านล่างและ:

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

และแกรม:

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

ดังนั้นฉันคิดว่านี่แสดงให้เห็นว่าวิธีเดียวที่จะนับ inodes คือโดย inode และเนื่องจากการนับไฟล์หมายถึงการนับไอโหนดคุณจึงไม่สามารถนับไอโหนดได้สองเท่า - การนับไฟล์อย่างถูกต้องไอโหนดจึงไม่สามารถนับได้มากกว่าหนึ่งครั้ง

อายุ:

ฉันพบสิ่งนี้เร็วกว่าและมันพกพาได้:

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

มันไม่จำเป็นต้องมี-execสำหรับทุกไดเรกทอรี - มันใช้เพียงหนึ่งในshกระบวนการ ell findและเป็นหนึ่งใน ฉันต้องทำให้set -- $globถูกต้องเพื่อรวม.hiddenไฟล์และสิ่งอื่น ๆ แต่มันใกล้และเร็วมาก คุณจะcdใส่อะไรก็ตามที่สารบบรูทของคุณควรตรวจสอบและออกไป

นี่คือตัวอย่างของการส่งออกของฉันทำงานจาก/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

ฉันใช้sedที่ด้านล่างตรงนั้นเพื่อตัดผลลัพธ์ 50 อันดับแรก headจะเร็วขึ้นแน่นอน แต่ฉันก็ตัดแต่ละบรรทัดถ้าจำเป็น:

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

มันดิบเป็นที่ยอมรับ แต่มันเป็นความคิด ควบคุมการใช้งานอุปกรณ์ฉันน้ำมันดิบทิ้ง2>stderrสำหรับทั้งสองfindและเข้าcd 2>/dev/nullมันเป็นเพียงสะอาดกว่ามองไปที่ข้อผิดพลาดสิทธิ์สำหรับไดเรกทอรีฉันไม่สามารถอ่านได้โดยไม่ต้องเข้าถึงราก - findบางทีฉันควรระบุว่า มันกำลังดำเนินการอยู่

ตกลงดังนั้นฉันจึงแก้ไขเปลือก globs ดังนี้:

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

ฉันเป็นจริงจะถามคำถามเกี่ยวกับวิธีการที่จะสามารถทำได้ แต่ขณะที่ผมกำลังพิมพ์ในชื่อคำถามเว็บไซต์ชี้ให้ฉันกับคำถามที่เกี่ยวข้องปัญหาที่แท้จริงและดูเถิด, สเตฟานได้แล้วชั่งน้ำหนักใน นั่นสะดวกมาก เห็นได้ชัดว่าได้[^.],รับการสนับสนุนเป็นอย่างดีไม่ใช่พกพาและคุณต้องใช้!bang.ฉันพบว่าในความคิดเห็นของ Stephane มี

อย่างไรก็ตามการดึงไฟล์ที่ซ่อนไม่เพียงพอ ดังนั้นผมจึงต้องsetสองครั้งในการสั่งซื้อเพื่อหลีกเลี่ยงการค้นหาสำหรับ positionals $globที่แท้จริง ถึงกระนั้นก็ดูเหมือนว่าจะไม่ส่งผลกระทบต่อประสิทธิภาพการทำงานทั้งหมดและมันจะเพิ่มทุกไฟล์ในไดเรกทอรีอย่างน่าเชื่อถือ


@ Graeme คุณรู้หรือไม่ว่าโซลูชันของเราไม่สามารถจัดการกับ inodes ได้ ไฟล์เหล่านั้นที่เรามีอยู่ในรายการมีแนวโน้มว่าจะเชื่อมโยงกันยาก ฉันคิดว่าฉันสามารถทำสิ่งนี้ได้ด้วยls -iและ ... ฉันเดาว่า ... อาจgrep... อาจจะ - คุณกำลังใช้-xdev,ซึ่งเป็นการเริ่มต้น ... uniqและsort?
mikeserv

duคุณกำลังใช้งานเวอร์ชันใดอยู่ ฉันduไม่มี--inodesตัวเลือก
Patrick

@Patrick - อาจต้องการอัปเดต - แต่ฉันได้อัปเดตโพสต์แล้ว
mikeserv

นั่นเป็นคุณสมบัติที่ทำให้มีเลือดออก :-) ฉันกำลังใช้งาน 8.21 ดูเหมือนว่าจะถูกเพิ่ม 2013-07-27: git.savannah.gnu.org/gitweb/ …
Patrick

นอกจากนี้หากคุณไม่รังเกียจคุณสามารถโพสต์สิ่งนั้นกับคำถามนี้ได้ไหม ฉันไม่คิดว่าฉันจะยอมรับเพราะมันไม่ได้พกพามาก แต่ฉันจะโหวตขึ้นและมันก็ดีที่มีวิธีแก้ไขปัญหาอื่น
Patrick

1

ทำไมไม่ใช้บางอย่างเช่น KDirStat ถึงแม้ว่ามันจะถูกเขียนขึ้นสำหรับ KDE แต่มันใช้งานได้ดีกับ GNOME เช่นกันมันให้มุมมองที่ดีที่สุดเกี่ยวกับจำนวนไฟล์ / dir และการใช้งานใน GUI


1
กำลังมองหาวิธีบรรทัดคำสั่ง
slm
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.