ฉันจะนับไฟล์ทั้งหมดซ้ำผ่านไดเรกทอรีได้อย่างไร


47

ฉันต้องการดูว่ามีกี่ไฟล์ในไดเรกทอรีย่อยเพื่อค้นหาว่าการใช้ inode ทั้งหมดอยู่ในระบบอย่างไร ฉันชอบทำสิ่งนี้เพื่อการใช้พื้นที่

du -sh /*

ซึ่งจะทำให้ฉันมีพื้นที่ที่ใช้ในไดเรกทอรีออกจากรูท แต่ในกรณีนี้ฉันต้องการจำนวนไฟล์ไม่ใช่ขนาด



ฉันคิดว่า "จำนวนไฟล์ที่อยู่ในไดเรกทอรีย่อยในนั้นมีไดเรกทอรีย่อย" เป็นการสร้างความสับสน หากระบุสิ่งที่คุณต้องการได้ชัดเจนยิ่งขึ้นคุณอาจได้รับคำตอบที่เหมาะกับใบเสร็จ
Steven D

@ สตีเฟ่นรู้สึกอิสระที่จะเขียนมันอีกครั้ง ... ฉันคิดว่าตัวอย่างของฉันdu -sh /*ทำให้มันค่อนข้างชัดเจนว่าฉันต้องการให้การนับเป็นอย่างไร สิ่งเดียวกันเพียงแค่นับไฟล์ไม่ได้เป็นไบต์
xenoterracide

ตามที่คุณพูดถึงการใช้งาน inode ฉันไม่เข้าใจว่าคุณต้องการนับจำนวนไฟล์หรือจำนวน inode ที่ใช้ ทั้งสองแตกต่างกันเมื่อฮาร์ดลิงก์มีอยู่ในระบบไฟล์ คำตอบส่วนใหญ่หากไม่ใช่ทั้งหมดให้จำนวนไฟล์ อย่าใช้มันในดิสก์สำรองข้อมูลของ Apple Time Machine
mouviciel

@mouviciel นี่ไม่ได้ใช้กับดิสก์สำรองข้อมูลและใช่ฉันคิดว่ามันอาจจะแตกต่างกัน แต่ในสภาพแวดล้อมที่ฉันอยู่ในนั้นมีฮาร์ดลิงก์ไม่กี่ตัวในทางเทคนิคฉันแค่ต้องรู้สึกถึงมัน คิดออกว่ามีใครบางคนกำลังเผาโควต้า inode
xenoterracide

คำตอบ:


60
find -maxdepth 1 -type d | while read -r dir; do printf "%s:\t" "$dir"; find "$dir" -type f | wc -l; done

ขอบคุณ Gilles และ xenoterracide สำหรับการแก้ไขความปลอดภัย / ความเข้ากันได้

ส่วนแรก: find -maxdepth 1 -type dจะส่งคืนรายการไดเรกทอรีทั้งหมดในไดเรกทอรีการทำงานปัจจุบัน สิ่งนี้ถูกส่งไปที่ ...

ส่วนที่สอง: while read -r dir; doเริ่มจาก while loop - ตราบใดที่ไพพ์เข้ามาในขณะที่เปิดอยู่ (ซึ่งจะส่งรายชื่อของไดเรกทอรีทั้งหมด) คำสั่ง read จะวางบรรทัดถัดไปในตัวแปร "dir" จากนั้นมันจะดำเนินต่อไป ...

ส่วนที่สาม: printf "%s:\t" "$dir";จะพิมพ์สตริงใน "$ dir" (ซึ่งถือหนึ่งในชื่อไดเรกทอรี) ตามด้วยแท็บ

ส่วนที่สี่: find "$dir -f file"สร้างรายการไฟล์ทั้งหมดภายในชื่อไดเรกทอรีที่เก็บไว้ใน "$ dir" รายการนี้ถูกส่งไป ..

ส่วนที่ห้า: wc -l;นับจำนวนบรรทัดที่ส่งไปยังอินพุตมาตรฐาน

ส่วนสุดท้าย: doneเพียงแค่สิ้นสุดในขณะที่วง

ดังนั้นเราจะได้รับรายชื่อของไดเรกทอรีทั้งหมดในไดเรกทอรีปัจจุบัน wc -lสำหรับแต่ละไดเรกทอรีที่เราสร้างรายการไฟล์ทั้งหมดที่อยู่ในนั้นเพื่อให้เราสามารถนับพวกเขาทั้งหมดที่ใช้ ผลลัพธ์จะมีลักษณะดังนี้:

./dir1: 234
./dir2: 11
./dir3: 2199
...

ใช้read -rเป็นธรรมดาreadถือ backslashes เป็นพิเศษ จากนั้นecho -en "$dir:\t"จะคล้ำแบ็กสแลชอีกครั้ง การแก้ไขแบบง่าย ๆ คือใช้printf '%s:\t' "$dir"แทน ถัดไป$dirควรเป็น"$dir"( ใช้เครื่องหมายคำพูดคู่ล้อมรอบการแทนที่ตัวแปรเสมอ)
Gilles 'หยุดความชั่วร้าย'

การแก้ไขต่อข้อเสนอแนะ @Gilesfind -maxdepth 1 -type d | while read -r dir; do printf "%s:\t" "$dir"; find "$dir" | wc -l; done
xenoterracide

2
ฉันกำลังเพิ่มsort -n -r -k2ส่วนท้ายของไดเรกทอรีจำนวนมากเพื่อให้ฉันรู้ว่าการใช้งานมากที่สุดอยู่
ที่ไหน

ส่วนที่สี่: ค้นหา "$ dir" ทำรายการไฟล์ทั้งหมดในชื่อไดเรกทอรีที่เก็บไว้ใน "$ dir" คุณลืมที่จะเพิ่ม-type fเพื่อทำให้ไฟล์เป็นรายการ:find -maxdepth 1 -type d | while read -r dir; do printf "%s:\t" "$dir"; find "$dir" -type f | wc -l; done
Krzysztof Boduch

@ krzysiek-boduch ขอบคุณ! ฉันอัพเดตคำตอบแล้ว
Shawn J. Goff

15

ลองfind . -type f | wc -lมันจะนับจำนวนไฟล์ทั้งหมดในไดเรกทอรีปัจจุบันรวมถึงไฟล์ทั้งหมดในไดเรกทอรีย่อย โปรดทราบว่าไดเรกทอรีทั้งหมดจะไม่ถูกนับเป็นไฟล์เฉพาะไฟล์ธรรมดาเท่านั้น


13

ต่อไปนี้เป็นการรวบรวมคำสั่งรายการที่มีประโยชน์ (แฮชอีกครั้งตามรหัสผู้ใช้ก่อนหน้า):

รายการโฟลเดอร์ที่มีจำนวนไฟล์:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" -type f | wc -l); printf "%4d : %s\n" $n "$dir"; done

รายการโฟลเดอร์ที่มีจำนวนไฟล์ที่ไม่เป็นศูนย์:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" -type f | wc -l); if [ $n -gt 0 ]; then printf "%4d : %s\n" $n "$dir"; fi; done

รายการโฟลเดอร์ที่มีจำนวนโฟลเดอร์ย่อย:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" -type d | wc -l); let n--; printf "%4d : %s\n" $n "$dir"; done

รายการโฟลเดอร์ที่มีจำนวนโฟลเดอร์ย่อยที่ไม่เป็นศูนย์:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" -type d | wc -l); let n--; if [ $n -gt 0 ]; then printf "%4d : %s\n" $n "$dir"; fi; done

รายการโฟลเดอร์ว่าง:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" | wc -l); let n--; if [ $n -eq 0 ]; then printf "%4d : %s\n" $n "$dir"; fi; done

รายการโฟลเดอร์ที่ไม่ว่างเปล่าที่มีจำนวนเนื้อหา:

find -maxdepth 1 -type d | sort | while read -r dir; do n=$(find "$dir" | wc -l); let n--; if [ $n -gt 0 ]; then printf "%4d : %s\n" $n "$dir"; fi; done

และ btw .. หากคุณต้องการให้ผลลัพธ์ของคำสั่งรายการใด ๆ เหล่านี้เรียงลำดับตามจำนวนรายการ .. ไพพ์คำสั่งลงในการเรียงลำดับ: "a-list-command" | sort -n
DolphinDream

12

ลอง:

find /path/to/start/at -type f -print | wc -l

เป็นจุดเริ่มต้นหรือถ้าคุณต้องการเรียกเก็บเงินผ่านไดเรกทอรีย่อยของไดเรกทอรีจริงๆ (และข้ามไฟล์ในไดเรกทอรีระดับบนสุดนั้น)

find `find /path/to/start/at -mindepth 1 -maxdepth 1 -type d -print` -type f -print | wc -l

+1 สำหรับบางสิ่ง | wc -l ... การนับจำนวนคำเป็นเครื่องมือเล็ก ๆ น้อย ๆ ที่ดีเช่น
โยฮัน

ใช่ แต่เพียงแค่นี้ 1 ไดเรกทอรี .... ฉันต้องการที่จะได้รับการนับสำหรับไดเรกทอรีทั้งหมดในไดเรกทอรีและฉันไม่ต้องการเรียกใช้แยกกันทุกครั้ง ... แน่นอนฉันคิดว่าฉันสามารถใช้วน ... แต่ฉันขี้เกียจ
xenoterracide

findทำงานซ้ำผ่านไดเรกทอรีย่อยทั้งหมดโดยค่าเริ่มต้น หากคุณต้องการให้การทำงานในหลาย ๆ สถานที่คุณสามารถระบุทั้งหมดของพวกเขาระหว่างและfind -type
Didier Trosset

อันที่สองอย่างแน่นอนไม่ทำงาน .... ฉันลองมัน / home 698035 ผมได้ ฉันควรเห็นตัวเลขประมาณ 6 ตัว
xenoterracide

มันใช้งานได้สำหรับฉัน - คุณแน่ใจหรือว่าคุณมีไฟล์แค่ 6 ไฟล์เท่านั้น/home? ฉันมั่นใจว่าคุณจะไม่ 100%
ร้องไห้ Havok

4

วิธีแก้ปัญหาต่อไปนี้นับจำนวนจริงของ inodes ที่ใช้เริ่มต้นจากไดเรกทอรีปัจจุบัน:

find . -print0 | xargs -0 -n 1 ls -id | cut -d' ' -f1 | sort -u | wc -l

ในการรับจำนวนไฟล์ของเซ็ตย่อยเดียวกันให้ใช้:

find . | wc -l

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


1
เป็นความคิดที่ดีที่ต้องคำนึงถึงการเชื่อมโยงอย่างหนัก สมมติว่า GNU พบคุณไม่ต้องทำหลายขั้นตอน: find -printf '%i\n' | sort -u | wc -l. หากคุณต้องการพกพาคุณต้องการfind . -exec ls -id {} + | cut …แทน
Gilles 'หยุดความชั่วร้าย'

2

OS X 10.6 findฉายาคำสั่งในคำตอบที่ได้รับการยอมรับเพราะมันไม่ได้ระบุเส้นทางสำหรับ ใช้แทน:

find . -maxdepth 1 -type d | while read -r dir; do printf "%s:\t" "$dir"; find "$dir" -type f | wc -l; done

2

ฉันรู้ว่าฉันมางานปาร์ตี้ช้า แต่ฉันเชื่อว่าbashวิธีแก้ปัญหา (หรือกระสุนอื่นที่ยอมรับดาวฤกษ์ดวงคู่) อาจเร็วกว่าในบางสถานการณ์:

shopt -s globstar    # to enable ** glob in bash
for dir in */; do a=( "$dir"/**/* ); printf "%s\t%s\n" "$dir:" "${#a[*]}"; done

เอาท์พุท:

d1/:    302
d2/:    24
d3/:    640
...

1

ลองดูสิ:

find -type d -print0 | xargs -0 -I {} sh -c 'printf "%s\t%s\n" "$(find "{}" -maxdepth 1 -type f | wc -l)" "{}"'

มันควรจะทำงานได้ดีเว้นแต่ชื่อไฟล์จะมีบรรทัดใหม่


recursive เกินไป ... ฉันแค่อยากเห็นระดับสูงสุดที่รวมทุกอย่างไว้ข้างใต้ รวมแล้ว ... นี่เป็นการพิมพ์ทุกไดเรกทอรี
xenoterracide

@xenoterracide: ลองเพิ่มทันทีหลังจากที่ครั้งแรก-maxdepth 1 findหากคุณต้องการรวมจำนวนไดเรกทอรีย่อยในการนับของคุณให้ลบ-type fที่ท้าย (ซึ่งควรมี! -type dอยู่แล้วจริงๆดังนั้นไฟล์ที่ไม่ใช่ไดเรกทอรีทั้งหมดจะรวมอยู่ด้วย)
Dennis Williamson

1

หากคุณมีการncduติดตั้ง (ต้องมีเมื่อคุณต้องการทำการล้างข้อมูลบางอย่าง) เพียงพิมพ์cไปที่ "สลับการแสดงผลของรายการย่อย" และCไปที่ "เรียงตามรายการ"


1
ฮ่า ๆ นี่ต้องเป็นคำตอบที่ได้รับการยอมรับมากที่สุด :)
x-yuri

0

du - โหนด

ฉันไม่แน่ใจว่าทำไมไม่มีใคร (รวมตัวเอง) ได้ตระหนักถึง:

du --inodes
--inodes
      list inode usage information instead of block usage

ฉันค่อนข้างมั่นใจว่านี่จะแก้ปัญหาของ OP ได้ ฉันเริ่มใช้มันมากมายเพื่อค้นหาว่าขยะทั้งหมดในไดรฟ์ขนาดใหญ่ของฉันคืออะไร (และถ่ายลงในดิสก์เก่า)

ข้อมูลเพิ่มเติม

หากคุณไม่ต้องการเรียกคืน (ซึ่งอาจเป็นประโยชน์ในสถานการณ์อื่น ๆ ) ให้เพิ่ม

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