बड़ी संख्या में फ़ाइलों के साथ निर्देशिका के लिए ls कमांड काम नहीं कर रहा है


70

मेरे पास एक निर्देशिका थी जिसमें लगभग 5 मिलियन फाइलें थीं । जब मैंने lsइस निर्देशिका के अंदर से कमांड को चलाने की कोशिश की , तो मेरे सिस्टम ने बड़ी मात्रा में मेमोरी का उपभोग किया और यह कुछ समय बाद लटका दिया गया। क्या lsकमांड का उपयोग करने के अलावा फ़ाइलों को सूचीबद्ध करने का एक कुशल तरीका है ?


11
सुनिश्चित करें कि आपके पास lsउस उपयोग के लिए कोई अन्य नाम नहीं है --colorया -Fइसका मतलब है कि lstat(2)प्रत्येक फ़ाइल के लिए करना होगा ।
स्टीफन चेज़लस

4
वैसे, लाखों फाइलों को एक ही निर्देशिका में संग्रहीत करना एक बुरा विचार है। यदि आप निर्देशिका लेआउट को नियंत्रित करते हैं, तो शायद इसे कुछ मानदंडों द्वारा विभाजित करें?
d33tah

क्या वह शुद्ध lsकॉल था या आपने विकल्पों का उपयोग किया था?
हौके लैगिंग

1
@ d33tah हाँ, 5 मिलियन बहुत है! मेरे रूट फाइल सिस्टम की सीमा 7 मिलियन है।
मिकेल

7
आउटपुट के लिए 5 मिलियन आइटम-किस तरह आप इसे देख रहे हैं - सरल लिस्टिंग देखने के लिए बहुत अधिक है - तो आप किसके लिए लिस्टिंग चाहते हैं?
user151019

जवाबों:


66

का उपयोग करके छँटाई से बचें:

ls --sort=none # "do not sort; list entries in directory order"

या, समकक्ष:

ls -U

10
मुझे आश्चर्य है कि कॉलम लेआउट कितना ओवरहेड करता है, भी। -1झंडे को जोड़ने से मदद मिल सकती है।
मिकेल

शायद ज्यादा नहीं, लेकिन हर थोड़ी मदद करता है, है ना? :)
मिकेल

1
@ मिकेल क्या यह सिर्फ एक अनुमान है, या आपने इसे मापा है? मेरे लिए ऐसा लगता है कि -1इससे भी अधिक समय लगता है ।
हौके लैगिंग

10
"-1" काफी मदद करता है। "ls -f -1" किसी भी स्टेट कॉल से बच जाएगा और तुरंत सब कुछ प्रिंट कर देगा। स्तंभ आउटपुट (जो टर्मिनल पर भेजते समय डिफ़ॉल्ट है) यह सब कुछ पहले बफर करता है। मेरे सिस्टम पर, 8 मिलियन फाइलों वाली निर्देशिका में btrfs का उपयोग करना (जैसा कि "seq 1 8000000 | xargs touch" द्वारा बनाया गया है), "समय ls -f -1 | wc -l" 5 सेकंड से कम समय लगता है, जबकि "समय ls -f -C | wc -l ”में 30 सेकंड से अधिक का समय लगता है।
स्कॉट लैम्ब

1
@ToolmakerSteve डिफ़ॉल्ट व्यवहार ( -Cजब stdout एक टर्मिनल है, -1जब यह एक पाइप है) भ्रामक है। जब आप प्रयोग कर रहे हों और माप रहे हों, तो आप आउटपुट को देखने के लिए फ्लिप करें (यह सुनिश्चित करने के लिए कि कमांड आपसे क्या उम्मीद करता है) और इसे दबा रहा है (टर्मिनल एप्लिकेशन के थ्रूपुट के भ्रमित कारक से बचने के लिए)। बेहतर आदेशों दोनों मोड में एक ही तरह से व्यवहार का उपयोग करने के, तो स्पष्ट रूप से के माध्यम से उत्पादन प्रारूप को परिभाषित -1, -C, -l, आदि
स्कॉट भेड़ का बच्चा

47

lsवास्तव में फाइलें छांटते हैं और उन्हें सूचीबद्ध करने की कोशिश करते हैं जो एक विशाल ओवरहेड बन जाता है यदि हम एक निर्देशिका के अंदर एक लाख से अधिक फाइलों को सूचीबद्ध करने की कोशिश कर रहे हैं। जैसा कि इस लिंक में बताया गया है , हम फ़ाइलों का उपयोग straceया findसूचीबद्ध कर सकते हैं। हालाँकि, वे विकल्प भी मेरी समस्या के लिए प्रतिकूल थे क्योंकि मेरे पास 5 मिलियन फाइलें थीं। कुछ गुगली करने के बाद, मैंने पाया कि यदि हम निर्देशिकाओं का उपयोग करते हुए सूचीबद्ध करते हैं getdents(), तो यह तेज़ होना चाहिए, क्योंकि ls, findऔर Pythonपुस्तकालयों का उपयोग readdir()धीमा है, लेकिन getdents()नीचे का उपयोग करता है।

हम यहाँgetdents() से उपयोग कर फाइलों को सूचीबद्ध करने के लिए C कोड पा सकते हैं :

/*
 * 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);
}

सी प्रोग्राम को उपरोक्त निर्देशिका में कॉपी करें जिसमें फ़ाइलों को सूचीबद्ध करने की आवश्यकता है। फिर नीचे दिए गए कमांड को निष्पादित करें।

gcc  getdents.c -o getdents
./getdents

समय का उदाहरण : सिस्टम कॉन्फ़िगरेशन पर निर्भर करते हुए, getdentsबहुत तेजी से हो सकता ls -fहै। यहाँ कुछ समय एक कम्प्यूटेशन क्लस्टर में NFS माउंट पर 500k फ़ाइलों वाली निर्देशिका को सूचीबद्ध करने के लिए 40x की गति वृद्धि का प्रदर्शन कर रहे हैं। प्रत्येक कमांड को तत्काल उत्तराधिकार में 10 बार चलाया गया था, पहले getdents, फिर ls -f। पहला रन अन्य सभी की तुलना में काफी धीमा है, शायद एनएफएस कैशिंग पेज दोष के कारण। (एक तरफ: इस माउंट पर, d_typeक्षेत्र अविश्वसनीय है, इस अर्थ में कि कई फाइलें "अज्ञात" प्रकार के रूप में दिखाई देती हैं)

command: getdents $bigdir
usr:0.08 sys:0.96  wall:280.79 CPU:0%
usr:0.06 sys:0.18  wall:0.25   CPU:97%
usr:0.05 sys:0.16  wall:0.21   CPU:99%
usr:0.04 sys:0.18  wall:0.23   CPU:98%
usr:0.05 sys:0.20  wall:0.26   CPU:99%
usr:0.04 sys:0.18  wall:0.22   CPU:99%
usr:0.04 sys:0.17  wall:0.22   CPU:99%
usr:0.04 sys:0.20  wall:0.25   CPU:99%
usr:0.06 sys:0.18  wall:0.25   CPU:98%
usr:0.06 sys:0.18  wall:0.25   CPU:98%
command: /bin/ls -f $bigdir
usr:0.53 sys:8.39  wall:8.97   CPU:99%
usr:0.53 sys:7.65  wall:8.20   CPU:99%
usr:0.44 sys:7.91  wall:8.36   CPU:99%
usr:0.50 sys:8.00  wall:8.51   CPU:100%
usr:0.41 sys:7.73  wall:8.15   CPU:99%
usr:0.47 sys:8.84  wall:9.32   CPU:99%
usr:0.57 sys:9.78  wall:10.36  CPU:99%
usr:0.53 sys:10.75 wall:11.29  CPU:99%
usr:0.46 sys:8.76  wall:9.25   CPU:99%
usr:0.50 sys:8.58  wall:9.13   CPU:99%

14
क्या आप समय में एक छोटा बेंचमार्क जोड़ सकते हैं जिसके लिए आपका मामला प्रदर्शित होता है ls?
बर्नहार्ड

1
मिठाई। और आप उनके नामों को सूचीबद्ध करने के बजाय केवल प्रविष्टियों (फाइलों) को गिनने के लिए एक विकल्प जोड़ सकते हैं (इस लिस्टिंग के लिए लाखों कॉलों को प्रिंटफ में सहेजना)।
५० बजे चक

29
आपको पता है कि आपकी निर्देशिका बहुत बड़ी है जब आपको इसकी सामग्री को सूचीबद्ध करने के लिए कस्टम कोड लिखना होगा ...
केसी

1
@ सीरीज़ को छोड़कर आपको नहीं करना है। यह सब getdentsबनाम के बारे में बात readdirयाद आती है।
मिकेल

9
आओ! इसमें पहले से ही 5 मिलियन फाइलें हैं। अपने कस्टम "ls" प्रोग्राम को किसी अन्य निर्देशिका में रखें।
जोहान

12

सबसे अधिक संभावित कारण यह धीमा है फ़ाइल प्रकार का रंग, आप इसके साथ \lsया /bin/lsरंग विकल्पों को बंद करने से बच सकते हैं।

यदि आपके पास वास्तव में एक dir में बहुत सारी फाइलें हैं, तो findइसके बजाय उपयोग करना भी एक अच्छा विकल्प है।


7
मुझे नहीं लगता कि इसे कम किया जाना चाहिए था। छंटनी एक समस्या है, लेकिन छंटाई के बिना भी, प्रत्येक फ़ाइल में ls -U --colorएक लंबा समय लगेगा stat। इसलिए दोनों सही हैं।
मिकेल

कलरिंग को बंद करने से उसके प्रदर्शन पर बहुत अधिक प्रभाव पड़ता है lsऔर कई अलग-अलग स्थानों पर यह डिफ़ॉल्ट रूप से अलियास हो जाता है .bashrc
विक्टर श्रोडर

हाँ, मैंने किया /bin/ls -Uऔर कुछ ही समय में आउटपुट मिला, बहुत लंबे समय से पहले इंतजार करने की तुलना में
खीबी

-3

मुझे पता है कि echo *ls की तुलना में बहुत तेजी से काम करता है। YMMV।


4
खोल छाँटेगा *। तो यह तरीका अभी भी 5 मिलियन फाइलों के लिए बहुत धीमा है।
मिकेल

3
@ मिकेल इससे अधिक, मुझे पूरा यकीन है कि 5 मिलियन फाइलें उस बिंदु पर हैं जहां ग्लोबिंग पूरी तरह से टूट जाएगा।
evilsoup

4
न्यूनतम फ़ाइल नाम की लंबाई (5 मिलियन फ़ाइलों के लिए) 3 वर्ण है (शायद 4 यदि आप अधिक सामान्य वर्णों से चिपके हुए हैं) प्लस सीमांकक = 4 वर्ण प्रति फ़ाइल, यानी 20 एमबी कमांड तर्क। यह आम 2 एमबी विस्तारित कमांड लाइन की लंबाई से अधिक है। Exec (और यहां तक ​​कि बिलियन) भी बुलेक करेंगे।
जोहान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.