จะนับจำนวนไฟล์ในแต่ละไดเร็กทอรีได้อย่างไร?


106

ฉันสามารถแสดงรายการไดเรกทอรีทั้งหมดโดย

find ./ -type d

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

find ./ -type d | xargs ls -l | wc -l

แต่นี่รวมจำนวนบรรทัดทั้งหมดที่ส่งคืนด้วย

find ./ -type d | xargs ls -l

มีวิธีการนับจำนวนไฟล์ในแต่ละไดเร็กทอรีหรือไม่?


คุณกำลังมองหาวิธีนับจำนวนไฟล์ในแต่ละไดเรกทอรีย่อยโดยตรง./หรือไม่?
Tuxdude

5
คำถามนอกประเด็นเป็นอย่างไร ?? ฉันต้องการเห็นความคิดเห็นของผู้มีสิทธิเลือกตั้งอย่างใกล้ชิดพร้อมเหตุผล! ถ้าเป็นเรื่องนอกประเด็นแล้วจะอยู่ที่ไหน? ผู้ใช้ขั้นสูง? ฉันไม่คิดอย่างนั้น ..
InfantPro'Aravind '

6
เชลล์สคริปต์แบทช์สคริปต์อยู่ภายใต้ขอบเขตการเขียนโปรแกรม!
InfantPro'Aravind '

ฉันกำลังจะโพสต์วิธีแก้ปัญหา Pythonic จากนั้นฉันสังเกตเห็นว่าคำถามถูกปิด
anatoly techtonik

โหวตให้เปิดอีกครั้ง อาจมีคำตอบอื่น ๆ ที่อาจเป็นประโยชน์ในหลาย ๆ สถานการณ์ (รวมถึงการเขียนโปรแกรมสคริปต์ซึ่งเป็นเหตุผลที่ฉันตอบคำถามนี้)
lepe

คำตอบ:


113

สมมติว่าคุณมี GNU พบให้มันค้นหาไดเรกทอรีและปล่อยให้ bash ทำส่วนที่เหลือ:

find . -type d -print0 | while read -d '' -r dir; do
    files=("$dir"/*)
    printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done

2
มันเป็นเพียงเวอร์ชันที่แตกต่างจากด้านบนดังนั้น: (คำใบ้: เรียงตามชื่อและใน csv) สำหรับ x in find . -maxdepth 1 -type d | sort; ทำ y = find $x | wc -l; ก้อง $ x, $ y; เสร็จสิ้น
pcarvalho

5
เยี่ยมมาก! วางไว้ในบรรทัดเดียว (จึงสะดวกสบายสำหรับการใช้งานโดยตรงในเชลล์):find . -type d -print0 | while read -d '' -r dir; do files=("$dir"/*); printf "%5d files in directory %s\n" "${#files[@]}" "$dir"; done
lucaferrario

14
ฉันต้องการรับจำนวนไฟล์ทั้งหมด (นับซ้ำ) ในแต่ละไดเรกทอรีย่อย การปรับเปลี่ยนนี้ให้ข้อมูลว่า: find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find $dir -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done
OmidS

1
@Kory ต่อไปนี้จะทำ:find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find "$dir" -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done | sort -rn -k1
OmidS

1
@OmidS oneliner ที่ยอดเยี่ยม แต่$dirควรอยู่ในเครื่องหมายคำพูดในความคิดเห็นแรกของคุณเพื่อจัดการชื่อ dir ด้วยช่องว่างอย่างถูกต้อง :find . -maxdepth 1 -type d -print0 | while read -d '' -r dir; do num=$(find "$dir" -ls | wc -l); printf "%5d files in directory %s\n" "$num" "$dir"; done
Radek Daniluk

184

สิ่งนี้จะพิมพ์จำนวนไฟล์ต่อไดเร็กทอรีสำหรับระดับไดเร็กทอรีปัจจุบัน:

du -a | cut -d/ -f2 | sort | uniq -c | sort -nr

9
วิธีแก้ปัญหาที่ดีที่สุด (และหรูหราที่สุด) หากต้องการแสดงจำนวนไฟล์ในไดเรกทอรีระดับบนสุดแบบเรียกซ้ำ
itoctopus

13
สิ่งนี้มีปัญหาสองประการ: นับหนึ่งไฟล์ต่อไดเร็กทอรีมากกว่าที่มีอยู่จริงและให้บรรทัดที่ไร้ประโยชน์ซึ่งมีขนาดของไดเร็กทอรีปัจจุบันเป็น "1 ขนาด " ทั้งสองสามารถแก้ไขได้ด้วยdu -a | sed '/.*\.\/.*\/.*/!d' | cut -d/ -f2 | sort | uniq -c. เพิ่ม| sort -nrเพื่อจัดเรียงตามจำนวนแทนชื่อไดเร็กทอรี
ของหวาน

3
ฉันต้องการชี้ให้เห็นว่าสิ่งนี้ใช้ได้กับ OSX ด้วย (เพียงแค่คัดลอกคำแนะนำของ Linux ไปวางใน OSX shell มักจะใช้ไม่ได้)
Pistos

2
มันดึงขนาดที่ไม่จำเป็นโดย du -a วิธีที่ดีกว่าคือใช้คำสั่ง find แต่แนวคิดหลักเหมือนกันทุก
ประการ

5
หา. - พิมพ์ f | ตัด -d / -f2 | เรียงลำดับ | uniq -c | sort -nr # แก้ไขปัญหาที่กล่าวถึงโดยขนม
jcomeau_ictx

29
find . -type f | cut -d/ -f2 | sort | uniq -c
  • find. -type f เพื่อค้นหารายการทั้งหมดของไฟล์ประเภท
  • cut -d/ -f2 เพื่อตัดโฟลเดอร์เฉพาะของพวกเขาออก
  • sort เพื่อจัดเรียงรายการชื่อพับ
  • uniq -c เพื่อส่งคืนจำนวนครั้งที่นับแต่ละชื่อพับ

8
นี่เป็นคำตอบที่ดีกว่าคำตอบที่ได้รับการยอมรับเนื่องจากคุณได้รับข้อมูลสรุปของไดเรกทอรีระดับบนสุด!
Jason Floyd

3
นี่ควรเป็นคำตอบที่ได้รับการยอมรับ ง่ายและเข้าใจได้
xssChauhan

1
คำตอบที่ดีที่สุดที่ควรยอมรับคือข้อนี้
loretoparisi

1
เรียบง่ายหรูหราและสมบูรณ์แบบสำหรับความต้องการของฉัน
RichR

สมบูรณ์แบบ. และสามารถขยายเพื่อนับในไดเร็กทอรีย่อยโดยการแทนที่ตัวระบุฟิลด์ด้วยรายการตัวระบุฟิลด์ เช่น ,:find . -type f | cut -d/ -f2,3 | sort | uniq -c
สาหร่าย

16

คุณสามารถจัดเรียงเพื่อค้นหาไฟล์ทั้งหมดลบชื่อไฟล์ทิ้งบรรทัดที่มีเพียงชื่อไดเร็กทอรีสำหรับแต่ละไฟล์จากนั้นนับจำนวนครั้งที่แต่ละไดเร็กทอรีปรากฏ:

find . -type f |
sed 's%/[^/]*$%%' |
sort |
uniq -c

gotcha เดียวในนี้คือถ้าคุณมีชื่อไฟล์หรือชื่อไดเร็กทอรีที่มีอักขระขึ้นบรรทัดใหม่ซึ่งไม่น่าจะเป็นไปได้ หากคุณต้องกังวลเกี่ยวกับการขึ้นบรรทัดใหม่ในชื่อไฟล์หรือชื่อไดเร็กทอรีฉันขอแนะนำให้คุณค้นหาและแก้ไขเพื่อไม่ให้มีการขึ้นบรรทัดใหม่


หากคุณสนใจในการนับไฟล์ในแต่ละไดเรกทอรีย่อยของไดเรกทอรีปัจจุบันการนับไฟล์ใด ๆ ในไดเรกทอรีย่อยใด ๆ พร้อมกับไฟล์ในไดเรกทอรีย่อยทันทีฉันจะปรับsedคำสั่งให้พิมพ์เท่านั้น ไดเรกทอรีระดับบนสุด:

find . -type f |
sed -e 's%^\(\./[^/]*/\).*$%\1%' -e 's%^\.\/[^/]*$%./%' |
sort |
uniq -c

รูปแบบแรกจะจับจุดเริ่มต้นของชื่อจุดเครื่องหมายทับชื่อจนถึงเครื่องหมายทับถัดไปและเครื่องหมายทับและแทนที่บรรทัดด้วยส่วนแรกเท่านั้นดังนั้น:

./dir1/dir2/file1

ถูกแทนที่ด้วย

./dir1/

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


1
สิ่งนี้ไม่แสดงชื่อไดเร็กทอรีที่ไม่มีไฟล์ใด ๆ ไม่แน่ใจว่าจำเป็นหรือไม่
Austin Phillips

จริงไม่จริง 'มันไม่สำคัญอย่างยิ่งที่จะแก้ไขให้ทำเช่นนั้นเนื่องจากชื่อไดเร็กทอรีว่างไม่ได้รับการรับรองว่าจะปรากฏในผลลัพธ์ของfind. บางคนอาจ: หากมีไฟล์dir1/dir2/dir3/file1แต่dir1/dir2มีไดเร็กทอรีย่อยเท่านั้น (ไม่มีไฟล์ธรรมดา) คุณสามารถสรุปได้ว่ามีอยู่ แต่ถ้าdir1/dir4ไม่มีไฟล์ชื่อก็จะไม่ปรากฏ
Jonathan Leffler

คำตอบที่มีประโยชน์มากหากคุณต้องการดูไดเร็กทอรีย่อยของไดเร็กทอรีปัจจุบัน
xixixao

เพิ่งแวะมากล่าวขอบคุณ 3 ปีหลังจากโพสต์สิ่งนี้ฉันต้องการนับโฟลเดอร์ระดับที่ 2 ต่อโฟลเดอร์ โพสต์ของคุณช่วยฉันได้หลายชั่วโมงในการแก้ไขกับ sed ค้นหาและใครจะรู้ว่ามีอะไรอีกบ้าง
Corvin

13

นี่เป็นวิธีหนึ่งที่ทำได้ แต่อาจไม่ได้ผลที่สุด

find -type d -print0 | xargs -0 -n1 bash -c 'echo -n "$1:"; ls -1 "$1" | wc -l' --

ให้เอาต์พุตเช่นนี้โดยมีชื่อไดเร็กทอรีตามด้วยจำนวนรายการในไดเร็กทอรีนั้น โปรดทราบว่าจำนวนผลลัพธ์จะรวมรายการไดเร็กทอรีด้วยซึ่งอาจไม่ใช่สิ่งที่คุณต้องการ

./c/fa/l:0
./a:4
./a/c:0
./a/a:1
./a/a/b:0

ดูเหมือนว่ามีราคาแพงมากในการเรียกใช้คำสั่ง 3 ( bash, ls, wc) findสำหรับแต่ละไดเรกทอรีพบโดย
Jonathan Leffler

@JonathanLeffler เห็นด้วยเพราะฉะนั้นบรรทัดแรกของคำตอบของฉัน ทางออกของคุณดีกว่า
Austin Phillips

เจ๋งนี่คือสิ่งที่ฉันกำลังมองหาฉันขอถามว่า '-' ในตอนท้ายคืออะไร?
เมื่อ

1
@once The - เป็นของคำสั่ง bash ซึ่งจะถูกสร้างโดย xargs จากman bash, A -- signals the end of options and disables further option processing. ในกรณีนี้จะป้องกันไม่ให้ไฟล์ชื่อผิดที่พบซึ่งเป็นส่วนหนึ่งของการค้นหากลายเป็นส่วนหนึ่งของการประมวลผลอาร์กิวเมนต์สำหรับ bash
Austin Phillips

8

ทางออกของคนอื่นมีข้อเสียเปรียบอย่างใดอย่างหนึ่ง

find -type d -readable -exec sh -c 'printf "%s " "$1"; ls -1UA "$1" | wc -l' sh {} ';'

คำอธิบาย:

  • -type d: เราสนใจในไดเรกทอรี
  • -readable: เราต้องการให้พวกเขาถ้ามันเป็นไปได้ที่จะแสดงรายการไฟล์ในพวกเขา โปรดทราบว่าfindจะยังคงแสดงข้อผิดพลาดเมื่อพยายามค้นหาไดเรกทอรีเพิ่มเติมในไดเรกทอรีเหล่านี้ แต่จะป้องกันการโทร-execหา
  • -exec sh -c BLAH sh {} ';': สำหรับแต่ละไดเร็กทอรีให้รันส่วนของสคริปต์นี้โดย$0ตั้งค่าเป็นshและ$1ตั้งค่าเป็นชื่อไฟล์
  • printf "%s " "$1": พิมพ์ชื่อไดเร็กทอรีแบบพกพาและย่อเล็กสุดตามด้วยเว้นวรรคไม่ใช่ขึ้นบรรทัดใหม่
  • ls -1UA: แสดงรายการไฟล์หนึ่งไฟล์ต่อบรรทัดตามลำดับไดเร็กทอรี (เพื่อหลีกเลี่ยงการหยุดไปป์) ยกเว้นเฉพาะไดเร็กทอรีพิเศษ.และ..
  • wc -l: นับเส้น

1
การแก้ไขเพื่อแสดงไฟล์นับเป็นอันดับแรกในบรรทัดและจัดเรียงตาม:find -type d -readable -exec sh -c 'ls -1UA "$1" | wc -l | tr -d "\n" ; printf "\t%s\n" "$1" ' sh {} ';' | sort -n
Evgeni Sergeev

มันดำเนินการเชลล์หลายครั้งจากนั้นจึงทำงานช้าและใช้ทรัพยากรสูง
Znik

6

คำตอบของเซบาสเตียนรุ่นแก้ไขเล็กน้อยโดยใช้findแทนdu(เพื่อยกเว้นค่าโสหุ้ยที่เกี่ยวข้องกับขนาดไฟล์ที่duต้องดำเนินการและไม่เคยใช้):

 find ./ -mindepth 2 -type f | cut -d/ -f2 | sort | uniq -c | sort -nr

-mindepth 2พารามิเตอร์ใช้เพื่อแยกไฟล์ในไดเร็กทอรีปัจจุบัน หากคุณลบออกคุณจะเห็นบรรทัดต่อไปนี้:

  234 dir1
  123 dir2
    1 file1
    1 file2
    1 file3
      ...
    1 fileN

(เหมือนกับduตัวแปร -based)

หากคุณต้องการนับไฟล์ในไดเร็กทอรีปัจจุบันด้วยให้ใช้เวอร์ชันปรับปรุงนี้:

{ find ./ -mindepth 2 -type f | cut -d/ -f2 | sort && find ./ -maxdepth 1 -type f | cut -d/ -f1; } | uniq -c | sort -nr

ผลลัพธ์จะเป็นดังนี้:

  234 dir1
  123 dir2
   42 .

5

ซึ่งสามารถทำได้ด้วยการวนลูปเหนือ ls แทนการค้นหา

for f in */; do echo "$f -> $(ls $f | wc -l)"; done

คำอธิบาย:

for f in */; - วนซ้ำไดเรกทอรีทั้งหมด

do echo "$f -> - พิมพ์ชื่อไดเรกทอรีแต่ละรายการ

$(ls $f | wc -l) - เรียก ls สำหรับไดเร็กทอรีนี้และนับบรรทัด


1
สิ่งนี้จะทำงานไม่ถูกต้องหากชื่อไดเร็กทอรีมีช่องว่าง
Xylol

ลองfor f ./* ; do echo $f $(ls "$f" | wc -l); done
4ndt3s

3

สิ่งนี้ควรส่งคืนชื่อไดเร็กทอรีตามด้วยจำนวนไฟล์ในไดเร็กทอรี

findfiles() {
    echo "$1" $(find "$1" -maxdepth 1 -type f | wc -l)
}

export -f findfiles

find ./ -type d -exec bash -c 'findfiles "$0"' {} \;

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

./ 6
./foo 1
./foo/bar 2
./foo/bar/bazzz 0
./foo/bar/baz 4
./src 4

export -fเป็นสิ่งจำเป็นเพราะ-execข้อโต้แย้งของfindไม่อนุญาตให้มีการดำเนินงานฟังก์ชั่นทุบตีเว้นแต่คุณเรียกทุบตีอย่างชัดเจนและคุณจำเป็นต้องส่งออกฟังก์ชั่นที่กำหนดไว้ในขอบเขตปัจจุบันเปลือกใหม่อย่างชัดเจน


สิ่งนี้ดูซับซ้อนเกินควร สำหรับฉันดูเหมือนว่ามันจะให้จำนวนสะสมสำหรับลำดับชั้นของไดเร็กทอรีเช่น./dir1/dir2/dir3(การนับไฟล์ในdir1และไดเร็กทอรีย่อยทั้งหมดเข้าด้วยกันแทนที่จะนับไฟล์dir1/dir2/dir3แยกจากไฟล์ในdir1/dir2และทั้งสองแยกจากไฟล์ใน/dir1)
Jonathan Leffler

ฉันเข้าใจว่านั่นคือสิ่งที่ผู้เขียนต้องการ หากไม่เป็นเช่นนั้นฉันยอมรับว่าคำตอบนั้นไม่เกี่ยวข้องกับคำถาม
Tuxdude

1
@JonathanLeffler - เอาล่ะอ่านคำถามอีกครั้งฉันรู้ว่าคุณพูดถูก - ได้แก้ไขคำตอบตามนั้น
Tuxdude

2

ฉันรวมคำตอบ @glenn แจ๊กแมนและ @ คำตอบของ pcarvalho (ในรายการแสดงความคิดเห็นมีสิ่งผิดปกติกับคำตอบ pcarvalho เพราะฟังก์ชั่นการควบคุมรูปแบบพิเศษของตัวละคร ' ` ' (backtick))

สคริปต์ของฉันสามารถยอมรับเส้นทางเป็น augument และเรียงลำดับรายชื่อไดเรกทอรีเป็นls -lยังสามารถจับปัญหาของ "ช่องว่างในชื่อไฟล์ว่า"

#!/bin/bash
OLD_IFS="$IFS"
IFS=$'\n'
for dir in $(find $1 -maxdepth 1 -type d | sort); 
do
    files=("$dir"/*)
    printf "%5d,%s\n" "${#files[@]}" "$dir"
done
FS="$OLD_IFS"

คำตอบแรกของฉันใน stackoverflow และฉันหวังว่ามันจะช่วยใครสักคนได้ ^ _ ^



0

ฉันลองกับคนอื่น ๆ ที่นี่ แต่ลงเอยด้วยโฟลเดอร์ย่อยที่รวมอยู่ในจำนวนไฟล์เมื่อฉันต้องการไฟล์เท่านั้น ซึ่งจะพิมพ์./folder/path<tab>nnnด้วยจำนวนไฟล์โดยไม่รวมโฟลเดอร์ย่อยสำหรับแต่ละโฟลเดอร์ย่อยในโฟลเดอร์ปัจจุบัน

for d in `find . -type d -print` 
do 
  echo -e "$d\t$(find $d -maxdepth 1 -type f -print | wc -l)"
done

0

วิธีง่ายๆในการค้นหาไฟล์ประเภทที่กำหนดซ้ำ ๆ ในกรณีนี้ไฟล์. jpg สำหรับโฟลเดอร์ทั้งหมดในไดเร็กทอรีปัจจุบัน:

find . -name *.jpg -print | wc -l


0

คำสั่ง super fast miracle ซึ่งจะส่งผ่านไฟล์แบบวนซ้ำเพื่อนับจำนวนภาพในไดเร็กทอรีและจัดระเบียบเอาต์พุตตามนามสกุลรูปภาพ:

find . -type f | sed -e 's/.*\.//' | sort | uniq -c | sort -n | grep -Ei '(tiff|bmp|jpeg|jpg|png|gif)$'

เครดิต: https://unix.stackexchange.com/a/386135/354980


0

นี่อาจเป็นอีกวิธีหนึ่งในการเรียกดูโครงสร้างไดเร็กทอรีและให้ผลลัพธ์เชิงลึก

find . -type d  | awk '{print "echo -n \""$0"  \";ls -l "$0" | grep -v total | wc -l" }' | sh 

0

ฉันแก้ไขสคริปต์เพื่อที่จะไม่รวมทั้งหมด node_modulesไดเรกทอรีภายในรายการที่วิเคราะห์

สามารถใช้เพื่อตรวจสอบว่าจำนวนไฟล์ของโปรเจ็กต์เกินจำนวนสูงสุดที่โปรแกรมดูไฟล์สามารถจัดการได้หรือไม่

find . -type d ! -path "*node_modules*" -print0 | while read -d '' -r dir; do
    files=("$dir"/*)
    printf "%5d files in directory %s\n" "${#files[@]}" "$dir"
done

ในการตรวจสอบไฟล์สูงสุดที่ระบบของคุณสามารถรับชมได้:

cat /proc/sys/fs/inotify/max_user_watches

node_modules ควรเพิ่มโฟลเดอร์ในพา ธ ที่ยกเว้น IDE / เอดิเตอร์ของคุณในระบบที่ช้าและจำนวนไฟล์อื่น ๆ ไม่ควรเกินค่าสูงสุด (ซึ่งสามารถเปลี่ยนแปลงได้)


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