วิธีที่ดีที่สุดในการนับจำนวนไฟล์ในไดเรกทอรีคืออะไร


11

หากการวิเคราะห์เอาต์พุตlsเป็นอันตรายเพราะสามารถแยกอักขระที่ขี้ขลาด (ช่องว่าง\n, ... ) ออกได้วิธีที่ดีที่สุดที่จะทราบจำนวนไฟล์ในไดเรกทอรีคืออะไร

ฉันมักจะพึ่งพาfindเพื่อหลีกเลี่ยงการแยกวิเคราะห์นี้ แต่ในทำนองเดียวกันfind mydir | wc -lจะทำลายด้วยเหตุผลเดียวกัน

ตอนนี้ฉันกำลังทำงานกับ Solaris อยู่ แต่ฉันกำลังมองหาคำตอบที่พกพาสะดวกในทุกกรณีและเปลือกหอยที่แตกต่างกันมากที่สุด


3
ฉันไม่แน่ใจว่าเป็นสิ่งที่ซ้ำซ้อนฉันขาดอะไรไปหรือเปล่า
rahmu

1
สิ่งนี้อาจซ้ำซ้อน แต่ไม่ใช่คำถามที่ระบุ findคุณจะได้รับจำนวนไฟล์ซ้ำ (ใช้-maxdepth 1หากคุณไม่ต้องการให้find mydir -maxdepth 1 -type f -printf \\n | wc -lจัดการอักขระพิเศษในชื่อไฟล์เนื่องจากไฟล์เหล่านั้นไม่เคยพิมพ์ตั้งแต่แรก
Anthon

คำตอบ:


16

เคล็ดลับนี้ล่ะ?

find . -maxdepth 1 -exec echo \; | wc -l

ในฐานะที่เป็นแบบพกพาเป็นและfindwc


5
สิ่งนี้ไม่ทำงาน (มันแสดงn+1ไฟล์ในระบบ Debian ของฉัน) นอกจากนี้ยังไม่กรองไฟล์ปกติ
Chris Down

4
ฉันแค่ยกตัวอย่างทั่วไป มันใช้งานได้ แต่วิธีการทำงานขึ้นอยู่กับวิธีที่คุณปรับfindคำสั่งให้เหมาะกับความต้องการเฉพาะของคุณ ใช่อันนี้รวมถึงไดเรกทอรีทั้งหมดรวมถึง.(ซึ่งอาจเป็นสาเหตุที่คุณเห็นผลลัพธ์เป็นn+1)
rozcietrzewiacz

ฉันชอบเคล็ดลับนี้ฉลาดมาก; แต่ฉันประหลาดใจไม่มีวิธีง่าย ๆ ที่จะทำอย่างนั้น!
rahmu

3
@ChrisDown OP ไม่ได้ระบุการกรองสำหรับไฟล์ปกติขอจำนวนไฟล์ในไดเรกทอรี ในการกำจัดปัญหา n + 1 ให้ใช้find . -maxdepth 1 ! -name . -exec echo \; | wc -l; รุ่นเก่าบางรุ่นไม่ได้find -not
Arcege

3
โปรดทราบว่า-maxdepthไม่ใช่มาตรฐาน (ขณะนี้ส่วนขยาย GNU ยังรองรับการใช้งานอื่น ๆ ด้วย)
Stéphane Chazelas

11

ด้วย bash โดยไม่มียูทิลิตี้ภายนอกหรือลูป:

shopt -s dotglob
files=(*)
echo ${#files[@]}

ใน ksh แทนที่โดยshopt -s dotglob FIGNORE=.?(.)ใน zsh แทนที่มันด้วยsetopt glob_dotsหรือเอาการโทรและการใช้งานshopt files=(*(D))(หรือเพียงแค่วางสายหากคุณไม่ต้องการรวมไฟล์ dot) พกพาถ้าคุณไม่สนใจเกี่ยวกับไฟล์ dot:

set -- *
echo $#

หากคุณต้องการรวมไฟล์ dot:

set -- *
if [ -e "$1" ]; then c=$#; else c=0; fi
set .[!.]*
if [ -e "$1" ]; then c=$((c+$#)); fi
set ..?*
if [ -e "$1" ]; then c=$((c+$#)); fi
echo $c

2
ตัวอย่างแรกพิมพ์1สำหรับไดเร็กทอรีว่างเมื่อnullglobไม่ได้เปิดใช้งาน ใน zsh a=(*(DN));echo ${#a}ด้วยqualifier N( nullglob) จะไม่ส่งผลให้เกิดข้อผิดพลาดสำหรับไดเรกทอรีว่าง
nisetama

8
find . ! -name . -prune -print | grep -c /

ควรพกพาไปได้ในระบบหลังยุค 80

ที่นับรายการไดเรกทอรีทั้งหมดยกเว้น.และ..ในไดเรกทอรีปัจจุบัน

หากต้องการนับไฟล์ในไดเรกทอรีย่อยด้วย:

find .//. ! -name . | grep -c //

(อันนั้นควรพกพาได้แม้กระทั่ง Unix V6 (1975) เนื่องจากไม่ต้องการ-prune)


หนึ่งในคำตอบที่หายากแบบพกพาในหน้านี้หากไม่ใช่คำตอบเดียว
xhienne

ฉันตอบคำตอบนี้เมื่อวานนี้เพราะฉันพบว่ามันทำงานได้ดีสำหรับไดเรกทอรีอื่นนอกเหนือจากไดเรกทอรีปัจจุบัน ( find dirname ! -name dirname -prune -print) ฉันสงสัยมาตลอดว่ามีเหตุผลพิเศษอะไรบ้างที่จะใช้grep -c /แทนwc -l(ซึ่งอาจใช้โดยทั่วไปเพื่อนับ)
Anthony Geoghegan

1
find dirname ! -name dirnameไม่ทำงานหากมีไดเรกทอรีอื่น ๆ dirnameภายในที่มีชื่อ find dirname/. ! -name .ดีกว่าที่จะใช้ wc -lนับจำนวนบรรทัดชื่อไฟล์สามารถสร้างได้หลายบรรทัดเนื่องจากอักขระขึ้นบรรทัดใหม่นั้นใช้ได้เช่นเดียวกับชื่อไฟล์
Stéphane Chazelas

6

ลอง:

ls -b1A | wc -l

The -bจะมีอักขระที่ไม่สามารถพิมพ์ได้-Aจะแสดงไฟล์ทั้งหมดยกเว้น.และ..และหนึ่งตัวต่อบรรทัด (ค่าเริ่มต้นบนไพพ์ แต่ควรจะชัดเจน)

ตราบใดที่เรารวมภาษาสคริปต์ระดับสูงต่อไปนี้เป็นหนึ่งบรรทัดใน Python:

python -c 'import os; print len(os.listdir(os.sep))'

หรือเต็มไปด้วย 'ค้นหา':

python -c 'import os; print len([j for i in os.walk(os.sep) for j in i[1]+i[2]])'

1

Yoc สามารถใช้การก่อสร้างดังกล่าว:

I=0; for i in * ; do ((I++)); done ; echo $I

แต่ฉันกลัวคุณสามารถแก้ไขข้อผิดพลาดเหมือนArgument list too long.ในกรณีที่คุณมีไฟล์มากเกินไปในไดเรกทอรี อย่างไรก็ตามฉันทดสอบมันในไดเรกทอรีที่มีไฟล์หมื่นล้านไฟล์และมันใช้งานได้ดี


3
*นี้จะไม่ทำงานสำหรับไฟล์ที่ซ่อนทั้งเปลือกเว้นแต่มีการกำหนดค่าที่จะขยายผู้ที่มี
Lekensteyn

gnu find . -maxdepth 1 -type f | wc -l
Nikhil Mulley

4
@Rush: คำสั่งนี้ไม่ควรยก "รายการ arg ยาวเกินไป" ที่จะเกิดขึ้นด้วยคำสั่งภายนอก (ไม่เคยมีfor.
enzotib

1

คุณเคยพิจารณา Perl ซึ่งควรพกพาไปได้บ้าง?

สิ่งที่ต้องการ:

use File::Find;

$counter = 0;

sub wanted { 
  -f && ++$counter
}

find(\&wanted, @directories_to_search);
print "$counter\n";

0

ลองนี้ => การใช้lsกับ -i (สำหรับหมายเลขโหนด) & -F (ผนวกชื่อไดเรกทอรีด้วยตัวเลือก '/')

ls -ilF | egrep -v '/' | wc -l

0

ด้วยperlสายการบินเดียว (จัดรูปแบบใหม่เพื่อให้อ่านง่าย):

perl -e 'opendir($dh, ".");
         while ( readdir($dh) ) {$count++};
         closedir $dh;
         print "$count\n";'

หรือ

perl -e 'opendir($dh, ".");
         @files = readdir($dh);
         closedir $dh;
         print $#files+1,"\n";'

คุณสามารถใช้perlฟังก์ชั่นที่แก้ไขอาร์เรย์เช่นgrepหรือmapรุ่นที่สอง ดูตัวอย่างการใช้perldoc -f readdirgrep


0

รุ่นที่ง่ายที่สุดที่ฉันใช้ตลอดเวลาและไม่เคยมีปัญหาคือ: ls -b1 | wc -l


คุณอาจพบปัญหาหากชื่อไฟล์มี\nตัวอักษรขี้ขลาดหรืออื่น ๆ (ใช่มีบาง unices อนุญาตให้ทำเช่นนี้)
rahmu

1
ฉันลองวิธีนี้อย่างชัดเจนก่อนโพสต์คำตอบและไม่มีปัญหา ฉันใช้ตัวจัดการไฟล์ nautilus เพื่อเปลี่ยนชื่อไฟล์เพื่อให้มี \ n เพื่อลอง
ปีเตอร์

คุณพูดถูกมันไม่ทำงานอย่างนั้น ฉันไม่รู้ว่าฉันทำอะไรเมื่อทดสอบครั้งแรก ลองอีกครั้งและอัปเดตคำตอบของฉัน
ปีเตอร์

ไม่คำสั่งนั้นใช้ได้ แต่มีวิธีการแก้ปัญหาที่คล้ายกันและไฟล์ที่ซ่อนอยู่จะไม่ถูกนับ
xhienne

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