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


55

CentOS 5.9

ฉันเจอปัญหาเมื่อวันก่อนที่ไดเรกทอรีมีไฟล์จำนวนมาก เมื่อต้องการนับฉันวิ่งls -l /foo/foo2/ | wc -l

ปรากฎว่ามีมากกว่า 1 ล้านไฟล์ในไดเรกทอรีเดียว (เรื่องยาว - สาเหตุที่แท้จริงได้รับการแก้ไข)

คำถามของฉันคือ: มีวิธีที่เร็วกว่าในการนับหรือไม่ อะไรจะเป็นวิธีที่มีประสิทธิภาพที่สุดในการนับ?


5
ls -l|wc -lจะถูกปิดโดยหนึ่งเนื่องจากบล็อกทั้งหมดในบรรทัดแรกของการls -lส่งออก
โทมัส Nyman

3
@ThomasNyman จริง ๆ แล้วมันจะถูกปิดโดยหลายคนเพราะรายการหลอกจุดและ dotdot แต่สามารถหลีกเลี่ยงได้โดยใช้การ-Aตั้งค่าสถานะ -lยังเป็นปัญหาเนื่องจากข้อมูลเมตาของไฟล์การอ่านเพื่อสร้างรูปแบบรายการเพิ่มเติม การบังคับไม่ให้-lใช้งาน\lsเป็นตัวเลือกที่ดีกว่ามาก ( -1สันนิษฐานว่าเมื่อส่งออกไพพ์) ดูคำตอบของ Gillesสำหรับคำตอบที่ดีที่สุดที่นี่
Caleb

2
@Caleb ls -lไม่ส่งออกไฟล์ที่ซ่อนอยู่หรือรายการ.และ การส่งออกรวมถึงไฟล์ที่ซ่อนอยู่รวมและในขณะที่การส่งออกรวมถึงไฟล์ที่ซ่อนไม่รวมและ ในคำตอบ Gilles ของทุบตีตัวเลือกเปลือกทำให้เกิดการขยายตัวในการรวมไฟล์ที่ซ่อนไม่รวมและ ..ls -a ...ls -A ...dotglob ...
โทมัสนีแมน

คำตอบ:


61

คำตอบสั้น ๆ :

\ls -afq | wc -l

(ซึ่งรวมถึง.และ..เพื่อลบ 2)


เมื่อคุณแสดงรายการไฟล์ในไดเรกทอรีสามสิ่งทั่วไปอาจเกิดขึ้น:

  1. การระบุชื่อไฟล์ในไดเรกทอรี นี่เป็นสิ่งที่หลีกเลี่ยงไม่ได้: ไม่มีวิธีนับไฟล์ในไดเรกทอรีโดยไม่ต้องระบุ
  2. เรียงลำดับชื่อไฟล์ สัญลักษณ์ตัวแทนเชลล์และlsคำสั่งทำเช่นนั้น
  3. การเรียกstatเพื่อดึงข้อมูลเมตาเกี่ยวกับแต่ละรายการไดเรกทอรีเช่นไม่ว่าจะเป็นไดเรกทอรี

# 3 แพงที่สุดเนื่องจากต้องโหลด inode สำหรับแต่ละไฟล์ ในการเปรียบเทียบชื่อไฟล์ทั้งหมดที่จำเป็นสำหรับ # 1 จะถูกเก็บไว้ในบล็อกไม่กี่บล็อก # 2 ทำให้เสียเวลา CPU แต่มักจะไม่ใช่ตัวจัดการดีล

หากไม่มีการขึ้นบรรทัดใหม่ในชื่อไฟล์แบบง่ายls -A | wc -lจะบอกให้คุณทราบถึงจำนวนไฟล์ที่มีในไดเรกทอรี ระวังว่าถ้าคุณมีนามแฝงlsสิ่งนี้อาจทำให้เกิดการโทรไปที่stat(เช่นls --colorหรือls -Fจำเป็นต้องรู้ประเภทของไฟล์ที่ต้องมีการเรียกไปstat) ดังนั้นจากบรรทัดคำสั่งโทรcommand ls -A | wc -lหรือ\ls -A | wc -lเพื่อหลีกเลี่ยงนามแฝง

หากมีการขึ้นบรรทัดใหม่ในชื่อไฟล์การขึ้นบรรทัดใหม่จะแสดงรายการหรือไม่ขึ้นอยู่กับตัวแปร Unix coreutils ของ GNU และ BusyBox เริ่มต้นที่จะแสดงขึ้น?บรรทัดใหม่ดังนั้นมันจึงปลอดภัย

โทรls -fเพื่อแสดงรายการโดยไม่ต้องเรียงลำดับ (# 2) สิ่งนี้จะเปิดโดยอัตโนมัติ-a(อย่างน้อยในระบบที่ทันสมัย) -fตัวเลือกอยู่ใน POSIX แต่ด้วยสถานะตัวเลือก; การใช้งานส่วนใหญ่รองรับ แต่ไม่ใช่ BusyBox ตัวเลือก-qจะแทนที่อักขระที่ไม่สามารถพิมพ์ได้รวมถึงการขึ้นบรรทัดใหม่ด้วย?; มันเป็น POSIX แต่ไม่รองรับโดย BusyBox ดังนั้นให้ละเว้นหากคุณต้องการการสนับสนุน BusyBox โดยมีค่าใช้จ่ายในการโอเวอร์โหลดไฟล์ที่ชื่อมีอักขระขึ้นบรรทัดใหม่

หากไดเรกทอรีไม่มีไดเรกทอรีย่อยรุ่นส่วนใหญ่findจะไม่เรียกstatใช้รายการของตน (การเพิ่มประสิทธิภาพไดเรกทอรีใบไม้: ไดเรกทอรีที่มีจำนวนลิงค์ 2 ไม่สามารถมีไดเรกทอรีย่อยได้ดังนั้นfindไม่จำเป็นต้องค้นหาข้อมูลเมตาของรายการยกเว้น เงื่อนไขเช่น-typeต้องการ) ดังนั้นfind . | wc -lวิธีพกพาและรวดเร็วในการนับไฟล์ในไดเรกทอรีโดยที่ไดเรกทอรีนั้นไม่มีไดเรกทอรีย่อยและไม่มีชื่อไฟล์ใดมี newline

หากไดเรกทอรีไม่มีไดเรกทอรีย่อย แต่ชื่อไฟล์อาจมีการขึ้นบรรทัดใหม่ให้ลองหนึ่งในไดเรกทอรีเหล่านี้ (ไดเรกทอรีที่สองควรจะเร็วกว่าหากได้รับการสนับสนุน แต่อาจไม่เด่นชัด)

find -print0 | tr -dc \\0 | wc -c
find -printf a | wc -c

ในทางกลับกันอย่าใช้findถ้าไดเรกทอรีนั้นมีไดเรกทอรีย่อย: แม้แต่find . -maxdepth 1เรียกstatทุกรายการ (อย่างน้อยด้วย GNU find และ BusyBox find) คุณหลีกเลี่ยงการเรียงลำดับ (# 2) แต่คุณจ่ายราคาของการค้นหา inode (# 3) ที่ฆ่าประสิทธิภาพ

set -- *; echo $#ในเปลือกไม่มีเครื่องมือภายนอกคุณสามารถเรียกใช้นับไฟล์ในไดเรกทอรีปัจจุบันด้วย นี่เป็นจุดไฟล์ (ไฟล์ที่มีชื่อขึ้นต้นด้วย.) และรายงาน 1 แทนที่จะเป็น 0 ในไดเรกทอรีว่าง นี่เป็นวิธีที่เร็วที่สุดในการนับไฟล์ในไดเรกทอรีขนาดเล็กเพราะมันไม่จำเป็นต้องเริ่มโปรแกรมภายนอก แต่ (ยกเว้นใน zsh) เสียเวลาสำหรับไดเรกทอรีขนาดใหญ่เนื่องจากขั้นตอนการเรียงลำดับ (# 2)

  • ใน bash นี่เป็นวิธีที่เชื่อถือได้ในการนับไฟล์ในไดเรกทอรีปัจจุบัน:

    shopt -s dotglob nullglob
    a=(*)
    echo ${#a[@]}
    
  • ใน ksh93 นี่เป็นวิธีที่เชื่อถือได้ในการนับไฟล์ในไดเรกทอรีปัจจุบัน:

    FIGNORE='@(.|..)'
    a=(~(N)*)
    echo ${#a[@]}
    
  • ใน zsh นี่เป็นวิธีที่เชื่อถือได้ในการนับไฟล์ในไดเรกทอรีปัจจุบัน:

    a=(*(DNoN))
    echo $#a
    

    หากคุณมีชุดตัวเลือกให้แน่ใจว่าจะปิด:mark_dirsa=(*(DNoN^M))

  • ใน POSIX เชลล์ใด ๆ นี่เป็นวิธีที่เชื่อถือได้ในการนับไฟล์ในไดเรกทอรีปัจจุบัน:

    total=0
    set -- *
    if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
    set -- .[!.]*
    if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
    set -- ..?*
    if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
    echo "$total"
    

วิธีการทั้งหมดเหล่านี้เรียงลำดับชื่อไฟล์ยกเว้น zsh one


1
การทดสอบเชิงประจักษ์ของฉันใน> 1 ล้านไฟล์แสดงให้เห็นว่าfind -maxdepth 1สามารถก้าวไปได้อย่างง่ายดาย\ls -Uตราบใดที่คุณไม่ได้เพิ่มอะไรอย่างเช่นการ-typeประกาศที่ต้องทำการตรวจสอบเพิ่มเติม คุณแน่ใจหรือว่า GNU ค้นหาสายจริงstatหรือ แม้แต่การชะลอตัวของfind -typeมันก็ไม่มีอะไรเทียบได้กับจำนวนls -lbogs ถ้าคุณทำให้มันคืนรายละเอียดไฟล์ ในขณะที่ผู้ชนะความเร็วที่ชัดเจนกำลังzshใช้ glob การเรียงลำดับที่ไม่ใช่ (globs ที่เรียงลำดับนั้นช้ากว่า 2x lsในขณะที่อันที่ไม่ใช่การเรียงลำดับนั้นเร็วกว่า 2x) ฉันสงสัยว่าประเภทระบบไฟล์จะส่งผลอย่างมีนัยสำคัญหรือไม่
Caleb

@Caleb straceฉันวิ่ง นี่เป็นจริงเฉพาะในกรณีที่ไดเรกทอรีมีไดเรกทอรีย่อย: มิฉะนั้นfindการเพิ่มประสิทธิภาพของไดเรกทอรีใบไม้จะเริ่มต้นที่ (แม้จะไม่มี-maxdepth 1) ฉันควรจะกล่าวถึงสิ่งนั้น หลายสิ่งหลายอย่างอาจส่งผลต่อผลลัพธ์รวมถึงประเภทของระบบไฟล์ (การเรียกstatใช้ระบบไฟล์ที่มีราคาแพงกว่ามากซึ่งแสดงถึงไดเรกทอรีเป็นรายการเชิงเส้นมากกว่าในระบบแฟ้มที่แสดงถึงไดเรกทอรีเป็นต้นไม้) ไม่ว่าจะสร้าง inodes ทั้งหมดเข้าด้วยกันหรือไม่ บนดิสก์แคชเย็นหรือร้อน ฯลฯ
Gilles 'หยุดความชั่วร้าย'

1
ในอดีตls -fได้รับวิธีที่เชื่อถือได้เพื่อป้องกันการโทรstat- นี้มักจะเป็นเพียงแค่การอธิบายในวันนี้เป็น "การส่งออกไม่ได้เรียง" (ซึ่งก็ยังทำให้เกิด) และไม่รวมถึงและ. และไม่ใช่ตัวเลือกมาตรฐาน ..-A-U
Random832

1
หากคุณต้องการนับไฟล์ที่มีนามสกุลทั่วไป (หรือสตริงอื่น ๆ ) โดยเฉพาะการแทรกลงในคำสั่งจะกำจัดส่วนที่เกิน 2 นี่คือตัวอย่าง:\ls -afq *[0-9].pdb | wc -l
Steven C. Howell

FYI ด้วย ksh93 version sh (AT&T Research) 93u+ 2012-08-01บนระบบที่ใช้เดเบียนของฉันFIGNOREดูเหมือนจะไม่ทำงาน .และ..รายการที่จะถูกรวมเข้าแถวที่เกิด
Sergiy Kolodyazhnyy

17
find /foo/foo2/ -maxdepth 1 | wc -l

จะเร็วกว่าในเครื่องของฉันมาก แต่.มีการเพิ่มไดเรกทอรีภายในลงในการนับ


1
ขอบคุณ ฉันถูกบังคับให้ถามคำถามงี่เง่าว่าทำไมมันเร็วกว่า? เพราะมันไม่รบกวนคุณสมบัติไฟล์ค้นหา?
Mike B

2
ใช่นั่นคือความเข้าใจของฉัน ตราบใดที่คุณไม่ได้ใช้-typeพารามิเตอร์findควรเร็วกว่าls
โจเอลเทย์เลอร์

1
อืม .... ถ้าฉันเข้าใจเอกสารของการค้นหาดีจริง ๆ แล้วมันควรจะดีกว่าคำตอบของฉัน ใครก็ตามที่มีประสบการณ์มากกว่าสามารถยืนยันได้
Luis Machuca

เพิ่ม a -mindepth 1เพื่อละเว้นไดเร็กทอรีเอง
Stéphane Chazelas

8

ls -1Uก่อนที่ไพพ์จะใช้ทรัพยากรน้อยลงเล็กน้อยเนื่องจากไม่ได้พยายามเรียงลำดับรายการไฟล์ แต่จะอ่านไฟล์เหล่านั้นเนื่องจากไฟล์เหล่านั้นถูกจัดเรียงไว้ในโฟลเดอร์บนดิสก์ wcนอกจากนี้ยังผลิตส่งออกน้อยลงหมายถึงการทำงานน้อยสำหรับ

คุณสามารถใช้ls -fทางลัดที่มากหรือน้อยls -1aUก็ได้

ฉันไม่ทราบว่ามีวิธีที่ประหยัดทรัพยากรในการทำผ่านคำสั่งโดยไม่ต้อง piping หรือไม่


8
Btw, -1 จะถูกบอกเป็นนัยเมื่อเอาต์พุตไปที่
ไพพ์

@enzotib - มันคืออะไร? ว้าว ... มีคนเรียนรู้สิ่งใหม่ทุกวัน!
Luis Machuca

6

อีกจุดเปรียบเทียบ ในขณะที่ไม่ได้เป็น shell oneliner โปรแกรม C นี้ไม่ได้ทำอะไรที่ฟุ่มเฟือย โปรดทราบว่าไฟล์ที่ซ่อนจะถูกละเว้นเพื่อให้ตรงกับผลลัพธ์ของls|wc -l( ls -l|wc -lถูกปิดโดยหนึ่งเนื่องจากบล็อกทั้งหมดในบรรทัดแรกของการส่งออก)

#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <error.h>
#include <errno.h>

int main(int argc, char *argv[])
{
    int file_count = 0;
    DIR * dirp;
    struct dirent * entry;

    if (argc < 2)
        error(EXIT_FAILURE, 0, "missing argument");

    if(!(dirp = opendir(argv[1])))
        error(EXIT_FAILURE, errno, "could not open '%s'", argv[1]);

    while ((entry = readdir(dirp)) != NULL) {
        if (entry->d_name[0] == '.') { /* ignore hidden files */
            continue;
        }
        file_count++;
    }
    closedir(dirp);

    printf("%d\n", file_count);
}

การใช้readdir()stdio API จะเพิ่มโอเวอร์เฮดบางส่วนและไม่ให้คุณควบคุมขนาดของบัฟเฟอร์ที่ส่งผ่านไปยังการเรียกระบบพื้นฐาน ( getdentsบน Linux)
Stéphane Chazelas

3

คุณสามารถลอง perl -e 'opendir($dh,".");$i=0;while(readdir $dh){$i++};print "$i\n";'

มันน่าสนใจที่จะเปรียบเทียบการกำหนดเวลากับท่อเปลือกของคุณ


ในการทดสอบของฉันนี้ช่วยให้สวยมากว่าก้าวเดียวกันขณะที่ทั้งสามโซลูชั่นอื่น ๆ ที่เร็วที่สุด ( find -maxdepth 1 | wc -l, \ls -AU | wc -lและzshตาม glob การเรียงลำดับและไม่นับอาร์เรย์) พูดอีกอย่างก็คือมันจะทำให้ตัวเลือกต่าง ๆ มีความไร้ประสิทธิภาพเช่นการเรียงลำดับหรือการอ่านคุณสมบัติของไฟล์ภายนอก ฉันอยากจะบอกว่าเพราะคุณไม่ได้รับอะไรเลยมันไม่คุ้มค่าที่จะใช้วิธีการแก้ปัญหาที่ง่ายกว่านี้เว้นแต่คุณจะอยู่ในรูปแบบ perl เรียบร้อยแล้ว :)
Caleb

โปรดทราบว่านี่จะรวมรายการ.และ..ไดเรกทอรีในการนับดังนั้นคุณต้องลบสองรายการเพื่อรับจำนวนไฟล์จริง (และไดเรกทอรีย่อย) ใน Perl ทันสมัยperl -E 'opendir $dh, "."; $i++ while readdir $dh; say $i - 2'จะทำมัน
Ilmari Karonen

2

จากคำตอบนี้ฉันคิดได้ว่านี่เป็นวิธีแก้ปัญหาที่เป็นไปได้

/*
 * List directories using getdents() because ls, find and Python libraries
 * use readdir() which is slower (but uses getdents() underneath.
 *
 * Compile with 
 * ]$ gcc  getdents.c -o getdents
 */
#define _GNU_SOURCE
#include <dirent.h>     /* Defines DT_* constants */
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/syscall.h>

#define handle_error(msg) \
       do { perror(msg); exit(EXIT_FAILURE); } while (0)

struct linux_dirent {
   long           d_ino;
   off_t          d_off;
   unsigned short d_reclen;
   char           d_name[];
};

#define BUF_SIZE 1024*1024*5

int
main(int argc, char *argv[])
{
   int fd, nread;
   char buf[BUF_SIZE];
   struct linux_dirent *d;
   int bpos;
   char d_type;

   fd = open(argc > 1 ? argv[1] : ".", O_RDONLY | O_DIRECTORY);
   if (fd == -1)
       handle_error("open");

   for ( ; ; ) {
       nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
       if (nread == -1)
           handle_error("getdents");

       if (nread == 0)
           break;

       for (bpos = 0; bpos < nread;) {
           d = (struct linux_dirent *) (buf + bpos);
           d_type = *(buf + bpos + d->d_reclen - 1);
           if( d->d_ino != 0 && d_type == DT_REG ) {
              printf("%s\n", (char *)d->d_name );
           }
           bpos += d->d_reclen;
       }
   }

   exit(EXIT_SUCCESS);
}

คัดลอกโปรแกรม C ด้านบนลงในไดเรกทอรีซึ่งต้องการแสดงไฟล์ จากนั้นดำเนินการคำสั่งเหล่านี้:

gcc getdents.c -o getdents
./getdents | wc -l

1
บางสิ่ง: 1) หากคุณยินดีที่จะใช้โปรแกรมที่กำหนดเองสำหรับสิ่งนี้คุณก็อาจนับจำนวนไฟล์และพิมพ์จำนวน; 2) เพื่อเปรียบเทียบกับls -fไม่กรองd_typeเลยเพียงd->d_ino != 0; 3) ลบ 2 และ. ..
Matei David

ดูคำตอบที่เชื่อมโยงสำหรับตัวอย่างการกำหนดเวลาที่นี้คือ 40x ls -fเร็วกว่าได้รับการยอมรับ
Matei David

1

โซลูชัน bash-only ไม่ต้องการโปรแกรมภายนอก แต่ไม่ทราบว่ามีประสิทธิภาพมากเพียงใด:

list=(*)
echo "${#list[@]}"

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

@Caleb เฉพาะ ksh เวอร์ชันเก่าเท่านั้นที่มีข้อ จำกัด ดังกล่าว (และไม่สนับสนุนไวยากรณ์นั้น) AFAIK ในเชลล์อื่น ๆ ส่วนใหญ่ จำกัด เป็นเพียงหน่วยความจำที่มีอยู่ คุณมีประเด็นที่ว่ามันจะไร้ประสิทธิภาพโดยเฉพาะอย่างยิ่งในการทุบตี
Stéphane Chazelas

1

น่าจะเป็นวิธีที่มีประสิทธิภาพทรัพยากรมากที่สุดจะไม่เกี่ยวข้องกับการร้องขอกระบวนการภายนอก ดังนั้นฉันจะเดิมพัน ...

cglb() ( c=0 ; set --
    tglb() { [ -e "$2" ] || [ -L "$2" ] &&
       c=$(($c+$#-1))
    }
    for glb in '.?*' \*
    do  tglb $1 ${glb##.*} ${glb#\*}
        set -- ..
    done
    echo $c
)

1
มีตัวเลขที่สัมพันธ์กันไหม? สำหรับไฟล์กี่ไฟล์
smci

0

หลังจากแก้ไขปัญหาจากคำตอบของ @Joel ซึ่งจะเพิ่ม.เป็นไฟล์:

find /foo/foo2 -maxdepth 1 | tail -n +2 | wc -l

tailเพียงลบบรรทัดแรกออกซึ่งหมายความว่า.จะไม่ถูกนับอีกต่อไป


1
การเพิ่มท่อคู่หนึ่งเพื่อตัดwcอินพุตหนึ่งบรรทัดนั้นไม่ได้มีประสิทธิภาพมากเพราะค่าใช้จ่ายจะเพิ่มขึ้นตามขนาดของอินพุตเป็นเส้นตรง ในกรณีนี้ทำไมไม่ลดจำนวนครั้งสุดท้ายเพื่อชดเชยมันจะถูกปิดโดยหนึ่งซึ่งเป็นการดำเนินการเวลาคงที่:echo $(( $(find /foo/foo2 -maxdepth 1 | wc -l) - 1))
โทมัส Nyman

1
แทนที่จะป้อนข้อมูลจำนวนมากผ่านกระบวนการอื่นมันอาจจะเป็นการดีกว่าถ้าคุณทำคณิตศาสตร์บางอย่างในผลลัพธ์สุดท้าย let count = $(find /foo/foo2 -maxdepth 1 | wc -l) - 2
Caleb

0

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

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

ต่อไปนี้เป็นเวลาที่ใช้โดยคำสั่ง python ข้างต้นเปรียบเทียบกับคำสั่ง 'ls -Af'

~ / ทดสอบ $ time ls -Af | wc -l
399144

จริง 0m0.300s
ผู้ใช้ 0m0.104s
sys 0m0.240s
~ / ทดสอบ $ time python -c 'import os; print len ​​(os.listdir ("."))'
399142

จริง 0m0.249s
ผู้ใช้ 0m0.064s
sys 0m0.180s

0

ls -1 | wc -lเข้ามาในใจฉันทันที ไม่ว่าls -1Uจะเร็วกว่าls -1ทางวิชาการล้วน ๆ - ความแตกต่างควรเล็กน้อย แต่สำหรับไดเรกทอรีที่มีขนาดใหญ่มาก


0

หากต้องการยกเว้นไดเรกทอรีย่อยจากการนับนี่คือรูปแบบต่างๆของคำตอบที่ยอมรับจาก Gilles:

echo $(( $( \ls -afq target | wc -l ) - $( \ls -od target | cut -f2 -d' ') ))

ด้านนอก$(( ))ขยายตัวทางคณิตศาสตร์หักการส่งออกของสอง$( )subshell $( )จากครั้งแรก ที่แรก$( )ก็คือ Gilles 'จากด้านบน ครั้งที่สอง$( )แสดงจำนวนไดเรกทอรีที่ "เชื่อมโยง" ไปยังเป้าหมาย สิ่งนี้มาจากls -od(แทนที่ls -ldหากต้องการ) โดยที่คอลัมน์ที่แสดงรายการจำนวนฮาร์ดลิงก์นั้นมีความหมายพิเศษสำหรับไดเรกทอรี "การเชื่อมโยง" นับรวม., ..และไดเรกทอรีย่อยใด ๆ

ฉันไม่ได้ทดสอบประสิทธิภาพ แต่ดูเหมือนว่าจะคล้ายกัน จะเพิ่มสถิติของไดเรกทอรีเป้าหมายและค่าใช้จ่ายบางส่วนสำหรับ subshell และท่อเพิ่ม


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