প্রচুর সংখ্যক ফাইলের জন্য দ্রুত লিনাক্স ফাইল গণনা


136

যখন খুব বেশি সংখ্যক ফাইল (> 100,000) থাকে তখন আমি কোনও নির্দিষ্ট ডিরেক্টরিতে ফাইল সংখ্যা সন্ধান করার সর্বোত্তম উপায়টি বের করার চেষ্টা করি।

যখন অনেকগুলি ফাইল থাকে, সম্পাদন ls | wc -lকরতে কার্যকর হতে বেশ দীর্ঘ সময় লাগে। আমি বিশ্বাস করি এটি এর কারণ এটি সমস্ত ফাইলের নাম ফেরত দিচ্ছে। আমি যতটা সম্ভব ডিস্ক IO এর কম গ্রহণ করার চেষ্টা করছি।

আমি কিছু শেল এবং পার্ল স্ক্রিপ্ট নিয়ে পরীক্ষা করে দেখেছি কোনও লাভ হয়নি। কোন ধারনা?


2
নিশ্চিত হয়ে নিন যে আপনার "ls" / usr / bin / ls এবং কোনও অনুরাগী ব্যক্তির একটি উপনাম নয়।
গ্লেন জ্যাকম্যান

আকর্ষণীয় উত্তরের সাথে অনুরূপ প্রশ্নটি এখানে: সার্ভারফল্ট.কোশনস
২০২০১71/২০১

এটি উল্লেখ করার মতো বিষয় যে এই প্রশ্নের জন্য উপস্থাপিত সমস্ত সমাধান লিনাক্সের জন্য নির্দিষ্ট নয় তবে সমস্ত * এনআইএক্স-জাতীয় সিস্টেমে বেশ সাধারণ। সম্ভবত "লিনাক্স" ট্যাগটি মুছে ফেলা উপযুক্ত।
ক্রিস্টোফার শুল্টজ

উত্তর:


188

ডিফল্টরূপে lsনামগুলি বাছাই করে, এর মধ্যে অনেকগুলি থাকলে কিছু সময় নিতে পারে। সমস্ত নাম পড়া এবং সাজানো না হওয়া পর্যন্ত কোনও আউটপুট থাকবে না। ls -fবাছাই বন্ধ করতে বিকল্পটি ব্যবহার করুন ।

ls -f | wc -l

নোট করুন যে এটি সক্রিয় হবে -a, তাই ., ..দিয়ে শুরু, এবং অন্যান্য ফাইল .গণনা করা হবে।


11
+1 এবং আমি ভেবেছিলাম যে সম্পর্কে যা জানা উচিত তা আমি জানি ls
জনতা

5
ZOMG। 100K লাইনের বাছাই কিছুই নয় - প্রতিটি ফাইলের stat()কলের তুলনায় ls। এটি দ্রুত কাজ findকরে না stat()
ডমি 100001

12
ls -fহয় না stat()। তবে অবশ্যই উভয়ের lsএবং findকল stat()যখন নির্দিষ্ট অপশন যেমন ব্যবহার করা হয় ls -lবা find -mtime
4o

7
প্রসঙ্গে, একটি ছোট-ইশ স্লাইশোস্ট বাক্সে 2.5 মিলিয়ন jpgs গণনা করতে এটি 1-2 মিনিট সময় নেয়।
ফিলাফ্রেও

6
আপনি যদি গণনায় সাব-ডিরেক্টরিগুলি যুক্ত করতে চান তবেls -fR | wc -l
রায়ান ওয়ালস

62

দ্রুততম উপায় হ'ল একটি উদ্দেশ্য-নির্মিত প্রোগ্রাম, এর মতো:

#include <stdio.h>
#include <dirent.h>

int main(int argc, char *argv[]) {
    DIR *dir;
    struct dirent *ent;
    long count = 0;

    dir = opendir(argv[1]);

    while((ent = readdir(dir)))
            ++count;

    closedir(dir);

    printf("%s contains %ld files\n", argv[1], count);

    return 0;
}

ক্যাশে বিবেচনা না করে আমার পরীক্ষা করা থেকে, ক্যাশে-ভিত্তিক ডেটা স্কিউ এড়াতে আমি প্রায় প্রতিটি বার একই ডিরেক্টরিটির বিরুদ্ধে প্রায় 50 বার দৌড়েছি এবং মোটামুটি নিম্নলিখিত কর্মক্ষমতা নম্বর পেয়েছি (আসল ঘড়ির সময়):

ls -1  | wc - 0:01.67
ls -f1 | wc - 0:00.14
find   | wc - 0:00.22
dircnt | wc - 0:00.04

এটি শেষটি,, dircntউপরোক্ত উত্স থেকে সংকলিত প্রোগ্রাম।

সম্পাদনা 2016-09-26

জনপ্রিয় চাহিদার কারণে, আমি পুনরায় লিখেছি এই প্রোগ্রামটি পুনরাবৃত্ত হওয়ার জন্য, তাই এটি উপ-ডিরেক্টরিতে নেমে আসবে এবং পৃথকভাবে ফাইল এবং ডিরেক্টরি গণনাতে থাকবে।

যেহেতু এটি স্পষ্ট হয়েছে যে কিছু লোকেরা কীভাবে এটি করতে হয় তা জানতে চায় , তাই কী চলছে তা সুস্পষ্ট করার চেষ্টা করার জন্য কোডটিতে আমার অনেক মন্তব্য রয়েছে। আমি এটি লিখেছি এবং এটি 64৪-বিট লিনাক্সে পরীক্ষা করেছি, তবে এটি মাইক্রোসফ্ট উইন্ডোজ সহ কোনও পসিক্স-কমপ্লায়েন্ট সিস্টেমে কাজ করা উচিত । বাগ রিপোর্ট স্বাগত; আপনি যদি এটি আপনার এআইএক্স বা ওএস / 400 বা যে কোনও কিছুতে কাজ করতে না পান তবে আমি এটি আপডেট করে খুশি।

আপনি দেখতে পাচ্ছেন, এটি আসলটির চেয়ে অনেক জটিল এবং অগত্যা প্রয়োজনীয়: আপনি কোডটি খুব জটিল হয়ে উঠতে না চাইলে অবশ্যই কমপক্ষে একটি ফাংশন অবশ্যই পুনরুক্তি বলা যেতে পারে (যেমন একটি সাব-ডিরেক্টরী স্ট্যাক পরিচালনা করা এবং এটি একটি একক লুপে প্রক্রিয়াকরণ)। যেহেতু আমাদের ফাইলের প্রকারগুলি পরীক্ষা করতে হবে, বিভিন্ন ওএস, স্ট্যান্ডার্ড লাইব্রেরি ইত্যাদির মধ্যে পার্থক্য খেলতে আসে, তাই আমি একটি প্রোগ্রাম লিখেছি যেখানে এটি সংকলিত হবে এমন কোনও সিস্টেমে ব্যবহারের যোগ্য হওয়ার চেষ্টা করে।

খুব কম ত্রুটি পরীক্ষা করা আছে, এবং countফাংশনটি নিজেই সত্যই ত্রুটির প্রতিবেদন করে না। কেবলমাত্র কলগুলি যা সত্যই ব্যর্থ হতে পারে সেগুলি হ'ল opendirএবং stat(যদি আপনি ভাগ্যবান না হন এবং direntইতিমধ্যে ফাইল টাইপ রয়েছে এমন কোনও সিস্টেম থাকে)। আমি সাবডির প্যাথনামগুলির মোট দৈর্ঘ্য পরীক্ষা করার বিষয়ে ভৌগলিক নই, তবে তাত্ত্বিকভাবে, সিস্টেমটির চেয়ে কোনও দীর্ঘ পথের নামটির অনুমতি দেওয়া উচিত নয় PATH_MAX। যদি উদ্বেগ থাকে তবে আমি এটি সংশোধন করতে পারি, তবে এটি কেবলমাত্র আরও কোড যা সি লিখতে শেখা কাউকে ব্যাখ্যা করা দরকার এই প্রোগ্রামটি কীভাবে পুনরাবৃত্তির সাথে সাব-ডিরেক্টরিতে ডুব দেওয়া যায় তার উদাহরণ হতে পারে to

#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/stat.h>

#if defined(WIN32) || defined(_WIN32) 
#define PATH_SEPARATOR '\\' 
#else
#define PATH_SEPARATOR '/' 
#endif

/* A custom structure to hold separate file and directory counts */
struct filecount {
  long dirs;
  long files;
};

/*
 * counts the number of files and directories in the specified directory.
 *
 * path - relative pathname of a directory whose files should be counted
 * counts - pointer to struct containing file/dir counts
 */
void count(char *path, struct filecount *counts) {
    DIR *dir;                /* dir structure we are reading */
    struct dirent *ent;      /* directory entry currently being processed */
    char subpath[PATH_MAX];  /* buffer for building complete subdir and file names */
    /* Some systems don't have dirent.d_type field; we'll have to use stat() instead */
#if !defined ( _DIRENT_HAVE_D_TYPE )
    struct stat statbuf;     /* buffer for stat() info */
#endif

/* fprintf(stderr, "Opening dir %s\n", path); */
    dir = opendir(path);

    /* opendir failed... file likely doesn't exist or isn't a directory */
    if(NULL == dir) {
        perror(path);
        return;
    }

    while((ent = readdir(dir))) {
      if (strlen(path) + 1 + strlen(ent->d_name) > PATH_MAX) {
          fprintf(stdout, "path too long (%ld) %s%c%s", (strlen(path) + 1 + strlen(ent->d_name)), path, PATH_SEPARATOR, ent->d_name);
          return;
      }

/* Use dirent.d_type if present, otherwise use stat() */
#if defined ( _DIRENT_HAVE_D_TYPE )
/* fprintf(stderr, "Using dirent.d_type\n"); */
      if(DT_DIR == ent->d_type) {
#else
/* fprintf(stderr, "Don't have dirent.d_type, falling back to using stat()\n"); */
      sprintf(subpath, "%s%c%s", path, PATH_SEPARATOR, ent->d_name);
      if(lstat(subpath, &statbuf)) {
          perror(subpath);
          return;
      }

      if(S_ISDIR(statbuf.st_mode)) {
#endif
          /* Skip "." and ".." directory entries... they are not "real" directories */
          if(0 == strcmp("..", ent->d_name) || 0 == strcmp(".", ent->d_name)) {
/*              fprintf(stderr, "This is %s, skipping\n", ent->d_name); */
          } else {
              sprintf(subpath, "%s%c%s", path, PATH_SEPARATOR, ent->d_name);
              counts->dirs++;
              count(subpath, counts);
          }
      } else {
          counts->files++;
      }
    }

/* fprintf(stderr, "Closing dir %s\n", path); */
    closedir(dir);
}

int main(int argc, char *argv[]) {
    struct filecount counts;
    counts.files = 0;
    counts.dirs = 0;
    count(argv[1], &counts);

    /* If we found nothing, this is probably an error which has already been printed */
    if(0 < counts.files || 0 < counts.dirs) {
        printf("%s contains %ld files and %ld directories\n", argv[1], counts.files, counts.dirs);
    }

    return 0;
}

সম্পাদনা 2017-01-17

আমি @ ফ্লাইংকোডমোনকি দ্বারা প্রস্তাবিত দুটি পরিবর্তন সংযুক্ত করেছি:

  1. lstatপরিবর্তে ব্যবহার করুন stat। আপনি যে ডিরেক্টরিটি স্ক্যান করছেন সেগুলিতে ডিরেক্টরিগুলি সংযুক্ত থাকলে এটি প্রোগ্রামটির আচরণ পরিবর্তন করবে change পূর্ববর্তী আচরণটি ছিল (সংযুক্ত) উপ-ডিরেক্টরিটি তার ফাইল গণনাটিকে সামগ্রিক গণনায় যুক্ত করবে; নতুন আচরণটি হ'ল লিঙ্কযুক্ত ডিরেক্টরিটি একটি একক ফাইল হিসাবে গণ্য হবে এবং এর সামগ্রীগুলি গণনা করা হবে না।
  2. যদি কোনও ফাইলের পথ খুব দীর্ঘ হয় তবে একটি ত্রুটি বার্তা প্রেরণ করা হবে এবং প্রোগ্রামটি থামবে।

সম্পাদনা 2017-06-29

যে কোনও ভাগ্যের সাথে, এটি এই উত্তরের শেষ সম্পাদনা হবে :)

কোডটি পেতে কিছুটা সহজ করার জন্য আমি এই কোডটি একটি গিটহাবের সংগ্রহস্থলে অনুলিপি করেছি (অনুলিপি / পেস্টের পরিবর্তে, আপনি কেবল উত্সটি ডাউনলোড করতে পারেন ), এবং এটি কারও পক্ষে একটি টান জমা দিয়ে কোনও সংশোধন প্রস্তাব দেওয়া সহজ করে তোলে -গিটহাব থেকে অনুরোধ।

উত্স অ্যাপাচি লাইসেন্স ২.০ এর আওতায় পাওয়া যায়। প্যাচগুলি * স্বাগতম!


  • "প্যাচ" হ'ল আমার মতো পুরানো লোকেরা "পুল অনুরোধ" বলে।

2
শুধু মহান! ধন্যবাদ! এবং যারা অচেতন তাদের জন্য: আপনি টার্মিনালে উপরের কোডটি সংকলন করতে পারেন: gcc -o dircnt dircnt.cএবং ব্যবহারটি এরকম./dircnt some_dir
aesede

এই পুনরাবৃত্তি করার একটি সহজ উপায় আছে?
সিকি_

@ck_ অবশ্যই, এটি সহজেই পুনরাবৃত্ত হতে পারে। সমাধানটির জন্য আপনার কি সহায়তা দরকার, না আপনি পুরো বিষয়টি লিখতে চান?
ক্রিস্টোফার শুল্টজ

1
@ ক্রিস্টোফারশাল্টজ, আপনি উপরে প্রকাশিত মাপদণ্ড - প্রশ্নটির মধ্যে ডিরেক্টরিটি কত বড়?
ডম ভিনিয়ার্ড

1
আমি পাইথনে এটি সত্যিই ব্যবহার করতে চেয়েছিলাম তাই আমি এফএফকাউন্ট প্যাকেজ হিসাবে প্যাকেজ করেছি। কোডটি ক্রিস্টোফারশাল্টজ উপলভ্য করার জন্য ধন্যবাদ!
GjjvdBurg

35

আপনি কি চেষ্টা করেছেন? উদাহরণ স্বরূপ:

find . -name "*.ext" | wc -l

1
এটি বর্তমান ডিরেক্টরিতে পুনরাবৃত্তভাবে ফাইলগুলি সন্ধান করবে ।
o

আমার সিস্টেমে find /usr/share | wc -l(১৩~,০০০ ডলার ফাইল) ls -R /usr/share | wc -lপ্রতিটি প্রথম রান করার সময় (names 160,000 লাইনগুলি দির নাম, দির টোটাল এবং ফাঁকা লাইন) এর চেয়ে প্রায় 25% দ্রুত এবং পরবর্তী (ক্যাশেড) রানগুলির তুলনা করার সময় কমপক্ষে দ্বিগুণ দ্রুত।
পরবর্তী বিজ্ঞপ্তি না দেওয়া পর্যন্ত বিরতি দেওয়া হয়েছে।

11
যদি তিনি কেবল বর্তমান ডিরেক্টরিটি চান, পুরো গাছটি পুনরাবৃত্তভাবে নয়, তবে তিনি সন্ধানের জন্য -ম্যাক্সডেপথ 1 বিকল্প যুক্ত করতে পারেন।
ইগাস্টিন

3
আপনি যেভাবে ব্যবহার করছেন তার থেকে কারণটি findদ্রুততর বলে মনে হচ্ছে । যদি আপনি বাছাই বন্ধ করেন, এবং একইরকম পারফরম্যান্স রাখেন। lslslsfind
ক্রিস্টোফার শুল্টজ

17

40,000 ফাইলের বিপরীতে পরীক্ষা করুন, এলএস এবং পার্ল পরীক্ষা করেছেন: একই গতি (যদিও আমি ক্যাশে সাফ করার চেষ্টা করিনি):

[user@server logs]$ time find . | wc -l
42917

real    0m0.054s
user    0m0.018s
sys     0m0.040s
[user@server logs]$ time /bin/ls -f | wc -l
42918

real    0m0.059s
user    0m0.027s
sys     0m0.037s

এবং পার্ল ওপেনডির / রিডডিরের সাথে একই সময়:

[user@server logs]$ time perl -e 'opendir D, "."; @files = readdir D; closedir D; print scalar(@files)."\n"'
42918

real    0m0.057s
user    0m0.024s
sys     0m0.033s

দ্রষ্টব্য: আমি / bin / ls -f ব্যবহার করে উপন্যাস বিকল্পটি বাইপাস করতে নিশ্চিত করেছিলাম যা ফাইলের ক্রম এড়ানোর জন্য কিছুটা কমিয়ে ফেলতে পারে এবং -f। ls -f ছাড়া ফাইস / পার্লের চেয়ে দ্বিগুণ ধীর গতি ব্যতীত ls -f এর সাথে ব্যবহার করা হয়, একই সময়ে মনে হয়:

[user@server logs]$ time /bin/ls . | wc -l
42916

real    0m0.109s
user    0m0.070s
sys     0m0.044s

আমি সমস্ত অপ্রয়োজনীয় তথ্য ছাড়াই সরাসরি ফাইল সিস্টেমটি জিজ্ঞাসা করার জন্য কিছু স্ক্রিপ্ট চাই।

পিটার ভ্যান ডের হেইজডেন, গ্লেন জ্যাকম্যান এবং মার্ক4o এর উত্তরের ভিত্তিতে পরীক্ষাগুলি।

টমাস


5
আপনার অবশ্যই পরীক্ষার মধ্যে ক্যাশে সাফ করা উচিত। আমি প্রথমবারের মতো ls -l | wc -lকোনও ফোল্ডারে 1M ফাইল সহ 2.5 "এইচডিডি চালাচ্ছি , অপারেশনটি শেষ করতে প্রায় 3 মিনিট সময় লাগে The দ্বিতীয়বার এটি 12 সেকেন্ডের আইআরসি লাগে Also এছাড়াও এটি সম্ভবত আপনার ফাইল সিস্টেমের উপরও নির্ভর করতে পারে I ব্যবহার করছিলেন Btrfs
Behrang Saeedzadeh

ধন্যবাদ, পার্ল স্নিপেট আমার জন্য সমাধান। $ time perl -e 'opendir D, "."; @files = readdir D; closedir D; print scalar(@files)."\n"' 1315029 real 0m0.580s user 0m0.302s sys 0m0.275s
পাওআউট

5

আপনি আপনার প্রয়োজনীয়তার উপর ভিত্তি করে আউটপুট পরিবর্তন করতে পারেন, তবে এখানে একটি ব্যাশ ওয়ান-লাইনার আমি পুনরাবৃত্তভাবে সংখ্যায় নামযুক্ত ডিরেক্টরিগুলির ডিরেক্টরিতে ফাইলগুলির সংখ্যা গণনা এবং প্রতিবেদন করতে লিখেছিলাম।

dir=/tmp/count_these/ ; for i in $(ls -1 ${dir} | sort -n) ; { echo "$i => $(find ${dir}${i} -type f | wc -l),"; }

এটি প্রদত্ত ডিরেক্টরিতে সমস্ত ফাইল (ডিরেক্টরি নয়) এর জন্য পুনরাবৃত্তভাবে দেখায় এবং ফলাফলগুলি হ্যাশ-জাতীয় বিন্যাসে ফিরিয়ে দেয়। ফাইন্ড কমান্ডের সরল টুইটগুলি আপনাকে কী ধরণের ফাইলগুলিকে আরও নির্দিষ্ট গণনা করতে চাইছে ইত্যাদি তৈরি করতে পারে etc.

এরকম কিছুতে ফলাফল:

1 => 38,
65 => 95052,
66 => 12823,
67 => 10572,
69 => 67275,
70 => 8105,
71 => 42052,
72 => 1184,

1
উদাহরণটি পেয়েছি কিছুটা বিভ্রান্তির। আমি ভাবছিলাম কেন ডিরেক্টরি নামের পরিবর্তে বামে সংখ্যা ছিল? যদিও এর জন্য আপনাকে ধন্যবাদ, আমি এটি কয়েকটি ছোটখাটো টুইট দিয়ে ব্যবহার করে শেষ করেছি। (ডিরেক্টরি গণনা করা এবং বেস ফোল্ডারের নাম বাদ দেওয়া i আমি ইন $ (ls -1। | সাজানো-এন); cho প্রতিধ্বনি "$ i => $ ($ {i} | wc -l) সন্ধান করুন";}
TheJacobTaylor

বাম দিকের নম্বরগুলি আমার উদাহরণের ডেটা থেকে আমার ডিরেক্টরি নাম। দুঃখিত যে বিভ্রান্তিকর ছিল।
পরাক্রমশালী

1
ls -1 ${dir}আরও জায়গা ছাড়াই সঠিকভাবে কাজ করবে না। এছাড়াও, কোনও গ্যারান্টি নেই যে এর দ্বারা ফেরত নামটি lsপাঠানো যেতে পারে find, যেহেতু lsমানব সেবনের জন্য মুদ্রণযোগ্য অক্ষরগুলি এড়িয়ে যায়। ( mkdir $'oddly\nnamed\ndirectory'আপনি যদি একটি বিশেষ আকর্ষণীয় পরীক্ষা ক্ষেত্রে চান)। আপনি কেন এলএস (1) এর আউটপুট বিশ্লেষণ করবেন না তা
চার্লস ডাফি

4

আমার জন্য আশ্চর্যের বিষয় হল, খালি-হাড়ের সন্ধানগুলি ls -f এর সাথে অনেক তুলনীয়

> time ls -f my_dir | wc -l
17626

real    0m0.015s
user    0m0.011s
sys     0m0.009s

বনাম

> time find my_dir -maxdepth 1 | wc -l
17625

real    0m0.014s
user    0m0.008s
sys     0m0.010s

অবশ্যই, তৃতীয় দশমিক স্থানের মানগুলি আপনি যখনই এর কোনওটি প্রয়োগ করেন প্রতিবার কিছুটা বদলে যান, সুতরাং সেগুলি মূলত অভিন্ন। তবে findখেয়াল করুন যে এটি একটি অতিরিক্ত ইউনিট প্রদান করে, কারণ এটি প্রকৃত ডিরেক্টরিটি নিজেই গণনা করে (এবং যেমন পূর্বে উল্লিখিত হয়েছে, ls -fদুটি অতিরিক্ত ইউনিট প্রদান করে, যেহেতু এটিও গণনা করে এবং ..)।


4

কেবলমাত্র সম্পূর্ণতার জন্য এটি যুক্ত করুন। অবশ্যই সঠিক উত্তরটি ইতিমধ্যে অন্য কেউ পোস্ট করেছেন, তবে আপনি ট্রি প্রোগ্রাম সহ ফাইল এবং ডিরেক্টরিগুলির একটি গণনাও পেতে পারেন।

tree | tail -n 1শেষ লাইনটি পেতে কমান্ডটি চালান , যা "763 ডিরেক্টরি, 9290 ফাইল" এর মতো কিছু বলবে। এটি লুকানো ফাইলগুলি বাদ দিয়ে ফাইল এবং ফোল্ডারগুলিকে পুনরাবৃত্তভাবে গণনা করে, যা পতাকা সহ যুক্ত করা যায় -a। রেফারেন্সের জন্য, আমার কম্পিউটারে গাছের জন্য আমার পুরো বাড়ির দির, যা 24777 ডিরেক্টরি, 238680 ফাইল ছিল তা গণনা করতে 4.8 সেকেন্ড সময় নিয়েছিল। find -type f | wc -l৫.৩ সেকেন্ড সময় নিয়েছে, আধা সেকেন্ড বেশি সময় নিয়েছে তাই আমার ধারণা গাছটি বেশ প্রতিযোগিতামূলক গতি অনুযায়ী wise

যতক্ষণ না আপনার কোনও সাবফোল্ডার না থাকে ততক্ষণ ফাইলগুলি গণনা করার জন্য ট্রি একটি দ্রুত এবং সহজ উপায়।

এছাড়াও, এবং সম্পূর্ণরূপে এটি মজাদার জন্য, আপনি tree | grep '^├'কেবল বর্তমান ডিরেক্টরিতে কেবল ফাইল / ফোল্ডার দেখানোর জন্য ব্যবহার করতে পারেন - এটি মূলত এর একটি খুব ধীর সংস্করণ ls


Brew install tailওএস এক্সের জন্য
আনফুন বিড়াল

@TheUnfunCat tailইতিমধ্যে আপনার ম্যাক ওএস এক্স সিস্টেমে ইনস্টল করা উচিত।
ক্রিস্টোফার শুল্টজ

4

দ্রুত লিনাক্স ফাইল গণনা

আমি জানি সবচেয়ে দ্রুত লিনাক্স ফাইল গণনা

locate -c -r '/home'

নেই কোন , grep ডাকা প্রয়োজন নেই! তবে উল্লিখিত হিসাবে আপনার কাছে একটি নতুন ডাটাবেস থাকা উচিত (ক্রোন জব দ্বারা প্রতিদিন আপডেট হওয়া বা ম্যানুয়াল দ্বারা sudo updatedb)।

মানুষ সনাক্ত থেকে

-c, --count
    Instead  of  writing  file  names on standard output, write the number of matching
    entries only.

অতিরিক্ত আপনার জানা উচিত যে এটি ডিরেক্টরিগুলিও ফাইল হিসাবে গণ্য করে!


বিটিডাব্লু: আপনি যদি আপনার সিস্টেমের ধরণে আপনার ফাইল এবং ডিরেক্টরিগুলির একটি ওভারভিউ চান

locate -S

এটি ডিরেক্টরি, ফাইল ইত্যাদির সংখ্যা আউটপুট করে


নোট করুন যে আপনাকে অবশ্যই নিশ্চিত করতে হবে যে ডাটাবেসটি আপ-টু-ডেট রয়েছে
ফুচলভি

1
LOL যদি আপনার ইতিমধ্যে একটি ডাটাবেসে সমস্ত গণনা থাকে তবে আপনি অবশ্যই দ্রুত গণনা করতে পারবেন। :)
ক্রিস্টোফার শুল্টজ

3

এখানে কোনও উত্তর সম্পর্কে মন্তব্য করার মতো যথেষ্ট খ্যাতি পয়েন্ট না থাকায় এটি এখানে লেখার জন্য , তবে আমার নিজের উত্তরটি ছেড়ে দেওয়ার অনুমতি দেওয়া হয়েছে , যা কোনও অর্থ হয় না। যাই হোক ...

সংক্রান্ত ক্রিস্টোফার সুল্ত্জ উত্তর , আমি পরিবর্তন করার পরামর্শ দিই পরিসংখ্যান থেকে lstat এবং সম্ভবত এড়ানোর বাফার ওভারফ্লো করার জন্য একটি সীমা-যাচাই যোগ:

if (strlen(path) + strlen(PATH_SEPARATOR) + strlen(ent->d_name) > PATH_MAX) {
    fprintf(stdout, "path too long (%ld) %s%c%s", (strlen(path) + strlen(PATH_SEPARATOR) + strlen(ent->d_name)), path, PATH_SEPARATOR, ent->d_name);
    return;
}

Lstat ব্যবহার করার পরামর্শটি হ'ল নিম্নোক্ত সিমনলিঙ্কগুলি এড়িয়ে যাওয়া যা কোনও ডিরেক্টরিতে যদি কোনও প্যারেন্ট ডিরেক্টরিতে একটি সিমলিংক থাকে তবে চক্র হতে পারে।


2
মোডিং আপ করা কারণ এর ব্যবহারটি lstatএকটি ভাল পরামর্শ ছিল এবং এটির জন্য আপনি কর্মের প্রাপ্য। এই পরামর্শটি উপরে পোস্ট করা কোডগুলিতে এবং এখন, গিটহাবের সাথে সংযুক্ত করা হয়েছিল।
ক্রিস্টোফার

2

আপনি চেষ্টা করে দেখতে পারেন যদি ব্যবহার opendir()এবং readdir()Perlদ্রুততর। এই ফাংশন উদাহরণ জন্য এখানে দেখুন


2
ব্যবহার: পার্ল -e 'ওপেনডির ডি, ";" @ ফাইলস = রিডডির ডি; ক্লোডির ডি; মুদ্রণ স্কেলার (@ ফাইলস) '
গ্লেন জ্যাকম্যান

2

এখানে এই উত্তরটি খুব বড়, খুব নেস্টেড ডিরেক্টরিগুলির জন্য এই পৃষ্ঠার প্রায় সমস্ত কিছুর চেয়ে দ্রুততর:

https://serverfault.com/a/691372/84703

locate -r '.' | grep -c "^$PWD"


1
খুশী হলাম। যেহেতু আপনার কাছে ইতিমধ্যে সমস্ত ফাইলের একটি আপ-টু-ডেট ডিবি রয়েছে, তাই এটি আর ফেরার দরকার নেই। তবে দুর্ভাগ্যক্রমে, আপনাকে অবশ্যই নিশ্চিত করতে হবে যে আপডেটেড কমান্ডটি ইতিমধ্যে এই পদ্ধতির জন্য চালিত এবং সম্পন্ন হয়েছে।
ক্রিস রেড

আপনার গ্রেপ করার দরকার নেই। আবু_বুয়ার সমাধানেরlocate -c -r '/path' মতো ব্যবহার করুন
ফুক্লভিভি

2

আমি প্রতি এখানে came 10 কে ফাইল সহ 10 কে ডলার ফোল্ডারের একটি ডেটাসেটে ফাইলগুলি গণনা করার চেষ্টা করার সময় এসেছি। অনেক পদ্ধতির সাথে সমস্যা হ'ল তারা স্পষ্টতই 100 এম ফাইল স্থির করে, যা বয়সগুলি গ্রহণ করে।

আমি ক্রিস্টোফার-স্কাল্টজ দ্বারা পদ্ধতির প্রসারিত করার স্বাধীনতা নিয়েছিলাম যাতে এটি আর্গুমেন্টগুলির মাধ্যমে পাসিং ডিরেক্টরিগুলি সমর্থন করে (তাঁর পুনরাবৃত্ত পদ্ধতির পাশাপাশি স্ট্যাট ব্যবহার করে)।

নিম্নলিখিত ফাইলগুলিতে রাখুন dircnt_args.c:

#include <stdio.h>
#include <dirent.h>

int main(int argc, char *argv[]) {
    DIR *dir;
    struct dirent *ent;
    long count;
    long countsum = 0;
    int i;

    for(i=1; i < argc; i++) {
        dir = opendir(argv[i]);
        count = 0;
        while((ent = readdir(dir)))
            ++count;

        closedir(dir);

        printf("%s contains %ld files\n", argv[i], count);
        countsum += count;
    }
    printf("sum: %ld\n", countsum);

    return 0;
}

এর পরে gcc -o dircnt_args dircnt_args.cআপনি এটি এইভাবে প্রার্থনা করতে পারেন:

dircnt_args /your/dirs/*

10 কে ফোল্ডারে 100 এম ফাইলগুলিতে উপরেরটি বেশ দ্রুত সম্পূর্ণ হয় (প্রথম রানের জন্য ~ 5 মিনিট, ক্যাশে ফলোআপ: ~ 23 এস)।

শুধুমাত্র অন্যান্য পদ্ধতির যে এক ঘন্টারও কম সময় সমাপ্ত ক্যাশে 1 সম্পর্কে মিনিট সঙ্গে ম ছিল: ls -f /your/dirs/* | wc -l। দির প্রতি কয়েকটি নতুন লাইনের মাধ্যমে গণনা বন্ধ রয়েছে যদিও ...

প্রত্যাশিত ব্যতীত, আমার কোনও চেষ্টাও findএক ঘণ্টার মধ্যে ফিরে আসেনি: - /


সি প্রোগ্রামার নয় এমন কারও কারও জন্য আপনি ব্যাখ্যা করতে পারেন কেন এটি দ্রুত হবে এবং কীভাবে এটি একই জিনিস না করে একই উত্তর পেতে সক্ষম?
mlissner

আপনাকে সি প্রোগ্রামার হওয়ার দরকার নেই, কেবল কোনও ফাইল স্থির করার অর্থ কী এবং ডিরেক্টরিগুলি কীভাবে উপস্থাপন করা হয় তা কেবল বুঝতে হবে: ডিরেক্টরিগুলি মূলত ফাইলের নাম এবং ইনোডের তালিকা। যদি আপনি কোনও ফাইল স্থির করেন তবে আপনি ড্রাইভের কোথাও থাকা ইনোড অ্যাক্সেস করতে পারেন উদাহরণস্বরূপ ফাইল-আকার, অনুমতি, ... এর মতো তথ্য পান। আপনি যদি দির প্রতি গণনাগুলিতে কেবল আগ্রহী হন তবে আপনাকে ইনোড তথ্য অ্যাক্সেস করার দরকার নেই, এটি আপনাকে অনেক সময় সাশ্রয় করতে পারে।
জার্ন হিজ

ওরাকল লিনাক্স, জিসিসি সংস্করণ 4.8.5 20150623 (রেড হ্যাট 4.8.5-28.0.1) (জিসিসি) ... আপেক্ষিক পাথ এবং রিমোট fs এর কারণ বলে মনে হচ্ছে
রন্টো

2

লিনাক্সের দ্রুততম উপায় (প্রশ্নটি লিনাক্স হিসাবে ট্যাগ করা হয়), সরাসরি সিস্টেম কল ব্যবহার করা। এখানে একটি ছোট প্রোগ্রাম রয়েছে যা কোনও ডিরেক্টরিতে ফাইলগুলি (কেবল, কোনও ডায়ার নয়) গণনা করে। আপনি কয়েক মিলিয়ন ফাইল গণনা করতে পারেন এবং এটি "এলএস-ফ" এর চেয়ে প্রায় 2.5 গুণ বেশি এবং ক্রিস্টোফার শুল্টজের উত্তরের চেয়ে প্রায় 1.3-1.5 গুণ বেশি দ্রুত।

#define _GNU_SOURCE
#include <dirent.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/syscall.h>

#define BUF_SIZE 4096

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

int countDir(char *dir) {


    int fd, nread, bpos, numFiles = 0;
    char d_type, buf[BUF_SIZE];
    struct linux_dirent *dirEntry;

    fd = open(dir, O_RDONLY | O_DIRECTORY);
    if (fd == -1) {
        puts("open directory error");
        exit(3);
    }
    while (1) {
        nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
        if (nread == -1) {
            puts("getdents error");
            exit(1);
        }
        if (nread == 0) {
            break;
        }

        for (bpos = 0; bpos < nread;) {
            dirEntry = (struct linux_dirent *) (buf + bpos);
            d_type = *(buf + bpos + dirEntry->d_reclen - 1);
            if (d_type == DT_REG) {
                // Increase counter
                numFiles++;
            }
            bpos += dirEntry->d_reclen;
        }
    }
    close(fd);

    return numFiles;
}

int main(int argc, char **argv) {

    if (argc != 2) {
        puts("Pass directory as parameter");
        return 2;
    }
    printf("Number of files in %s: %d\n", argv[1], countDir(argv[1]));
    return 0;
}

পিএস: এটি পুনরাবৃত্ত হয় না তবে এটি অর্জনের জন্য আপনি এটি পরিবর্তন করতে পারেন।


1
আমি নিশ্চিত নই যে আমি একমত যে এটি দ্রুত। সংকলকটি opendir/ এর সাথে যা কিছু করে আমি তা আবিষ্কার করতে পারি নি readdir, তবে আমার সন্দেহ হয় যে এটি প্রায় একই কোডে শেষ পর্যন্ত ফোটে। সিস্টেম কল করা সেইভাবে বহনযোগ্যও নয় এবং লিনাক্স এবিআই স্থিতিশীল না হওয়ায় একটি সিস্টেমে সংকলিত একটি প্রোগ্রামে অন্যটিতে সঠিকভাবে কাজ করার গ্যারান্টি দেওয়া হয় না (যদিও এটি কোনও * এনআইএক্স সিস্টেম আইএমও থেকে উত্স থেকে যে কোনও কিছু সংকলন করার পক্ষে মোটামুটি ভাল পরামর্শ) though )। যদি গতি কী হয় তবে এটি ভাল সমাধান যদি এটি প্রকৃতপক্ষে গতি উন্নত করে - আমি প্রোগ্রামগুলি পৃথকভাবে বেঞ্চমার্ক করি না।
ক্রিস্টোফার

1

lsফাইলের নাম বাছাই করতে আরও সময় ব্যয় করে, -fবাছাই অক্ষম করতে ব্যবহার করে কিছু সময় সাশ্রয় হবে:

ls -f | wc -l

অথবা আপনি ব্যবহার করতে পারেন find:

find . -type f | wc -l

0

আমি বুঝতে পেরেছি যে যখন আপনার কাছে প্রচুর পরিমাণে ডেটা থাকে তখন মেমরি প্রসেসিং ব্যবহার না করা কমান্ডগুলির "পাইপিং" করার চেয়ে দ্রুত হয়। সুতরাং আমি ফলাফলটি একটি ফাইলে সংরক্ষণ করেছি এবং এটি বিশ্লেষণ করার পরে

ls -1 /path/to/dir > count.txt && cat count.txt | wc -l

এটি দ্রুততম সমাধান নয় কারণ হার্ড ডিস্কগুলি অত্যন্ত ধীর। অন্যান্য আরও দক্ষ উপায়ে আপনি আগে বছর পোস্ট করা হয় হয়
phuclv

0

Ls / find এর জায়গায় আপনার "getdents" ব্যবহার করা উচিত

এখানে একটি খুব ভাল নিবন্ধ যা getdents পদ্ধতির বর্ণিত।

http://be-n.com/spw/you-can-list-a-million-files-in-a-directory-but-not-with-ls.html

এখানে এক্সট্রাক্ট:

ls এবং কার্যতঃ ডিরেক্টরি নির্দেশ করার প্রতিটি অন্যান্য পদ্ধতি (পাইথন ওএস.লিস্টডির সহ, সন্ধান করুন li) লিবিসি রিডডিয়ার () এ নির্ভর করুন। তবে readdir () কেবল একবার ডিরেক্টরি ডিরেক্টরিগুলি 32K পড়ে, যার অর্থ যদি আপনার একই ডিরেক্টরিতে প্রচুর ফাইল থাকে (যেমন ডিরেক্টরি ডিরেক্টরিতে 500M) থাকে তবে সমস্ত ডিরেক্টরি এন্ট্রিগুলি পড়তে এটি একটি অত্যন্ত দীর্ঘ সময় নিতে চলেছে বিশেষত একটি ধীর ডিস্কে। বিপুল সংখ্যক ফাইল ধারণকারী ডিরেক্টরিগুলির জন্য, আপনাকে রিডডির () উপর নির্ভর করে এমন সরঞ্জামগুলির চেয়ে আরও গভীর খনন করতে হবে। আপনাকে লিবিডির সাহায্যকারী পদ্ধতির পরিবর্তে সরাসরি গেটেন্টস () সিস্কেল ব্যবহার করতে হবে।

আমরা এখান থেকে গেটেন্টস () ব্যবহার করে ফাইলগুলির তালিকা তৈরি করতে সি কোডটি খুঁজে পেতে পারি :

একটি ডিরেক্টরিতে সমস্ত ফাইল দ্রুত তালিকাভুক্ত করতে আপনাকে দুটি পরিবর্তন করতে হবে।

প্রথমে এক্স থেকে 5 মেগাবাইটের মতো বাফারের আকার বাড়ান something

#define BUF_SIZE 1024*1024*5

তারপরে মূল লুপটি সংশোধন করুন যেখানে এটি ইনড == ০. সহ এন্ট্রিগুলি এড়িয়ে যাওয়ার জন্য ডিরেক্টরিতে প্রতিটি ফাইলের তথ্য মুদ্রণ করে adding

if (dp->d_ino != 0) printf(...);

আমার ক্ষেত্রে আমি কেবলমাত্র ডিরেক্টরিতে ফাইলের নামগুলি যত্নশীল তাই কেবল ফাইলের নাম মুদ্রণের জন্য আমি প্রিন্টফ () বিবৃতিটি আবারও লিখেছি।

if(d->d_ino) printf("%sn ", (char *) d->d_name);

এটি সঙ্কলন করুন (এটির জন্য কোনও বাহ্যিক গ্রন্থাগারের প্রয়োজন নেই, তাই এটি করা খুব সহজ)

gcc listdir.c -o listdir

এখন শুধু চালান

./listdir [directory with insane number of files]

নোট করুন যে লিনাক্স একটি রিড-ফরোয়ার্ড করে, তাই readdir()আসলে ধীর হয় না। এই পারফরম্যান্স লাভের জন্য বহনযোগ্যতা ছুঁড়ে ফেলার পক্ষে এটি বিশ্বাস করার আগে আমার দৃ figure় ব্যক্তিত্বের প্রয়োজন।
ফুজ

-1

আমি ডিরেক্টরিতে ফাইলের সংখ্যার পরিবর্তনের উপর নজর রাখতে নীচের কমান্ডটি পছন্দ করি।

watch -d -n 0.01 'ls | wc -l'

কমান্ডটি 0.1 সেকেন্ডের রিফ্রেশ রেট সহ ডিরেক্টরিতে থাকা ফাইলগুলির কোনও নম্বর রাখার জন্য একটি উইন্ডো খোলা রাখবে।


আপনি কি ls | wc -l0.01 সেকেন্ডে কয়েক হাজার বা কয়েক মিলিয়ন ফাইল সহ কোনও ফোল্ডারের কাজ শেষ করবেন? এমনকি আপনার lsঅন্যান্য সমাধানের তুলনায় অত্যন্ত কার্যকর। এবং ওপি কেবল গণনা পেতে চায়, বসে না বসে আউটপুট পরিবর্তনের দিকে তাকিয়ে থাকে
phuclv

আমরা হব. আমরা হব. আমি একটি মার্জিত সমাধান পেয়েছি যা আমার পক্ষে কাজ করে। আমি একই ভাগ করতে চাই, তাই করেছি। আমি জানি না লিনাক্সে 'ls' কমান্ড অত্যন্ত অযোগ্য। তার পরিবর্তে আপনি কী ব্যবহার করছেন? এবং 0.01s হ'ল রিফ্রেশ রেট। সময় নয়। আপনি যদি ঘড়ি ব্যবহার না করেন তবে ম্যান পেজগুলি দেখুন।
আনুপ টফ্ফি

আমি watchসেই মন্তব্যের পরে ম্যানুয়ালটি পড়েছি এবং দেখতে পেয়েছি যে 0.01s (0.1s নয়) একটি অবাস্তব সংখ্যা কারণ বেশিরভাগ পিসি স্ক্রিনের রিফ্রেশ হার কেবল 60Hz, এবং এটি কোনওভাবেই প্রশ্নের উত্তর দেয় না। ওপিতে "বিপুল সংখ্যক ফাইলের জন্য ফাস্ট লিনাক্স ফাইল গণনা" সম্পর্কে জিজ্ঞাসা করা হয়েছিল। আপনি পোস্ট করার আগে কোনও উপলভ্য উত্তর পড়েন নি
ফুচলভি

আমি উত্তরগুলি পড়েছি। তবে আমি যা পোস্ট করেছি তা হ'ল ডিরেক্টরিতে ফাইলের সংখ্যা পরিবর্তন করার ট্র্যাক রাখার একটি উপায়। উদাহরণস্বরূপ: এক অবস্থান থেকে অন্য জায়গায় ফাইল অনুলিপি করার সময় ফাইলের সংখ্যা পরিবর্তন রাখে। আমি পোস্টার পদ্ধতিটি দিয়ে একজন এটি ট্র্যাক রাখতে পারে। আমি সম্মত হলাম যে পোস্টটি আমি পূর্বের কোনও পোস্ট সংশোধন বা উন্নতি করতে পারিনি সেখানে।
আনুপ টফ্ফি

-2

প্রথম 10 টি ফাইলের হাইজাস্ট নম্বর সহ পরিচালক।

dir=/ ; for i in $(ls -1 ${dir} | sort -n) ; { echo "$(find ${dir}${i} \
    -type f | wc -l) => $i,"; } | sort -nr | head -10

3
এটি অবশ্যই বিস্ময়করভাবে দেখতে পরাশক্তিদের দ্বারা লিখিত উত্তরের (একই বাগ সহ) অনুরূপ । যদি আপনি অন্য কারও দ্বারা লিখিত কোড প্রসারিত বা সংশোধন করতে চলেছেন তবে তাদের জমা দেওয়া উপযুক্ত। আপনার উত্তরগুলিতে আপনি যে কোডটি ব্যবহার করছেন সেগুলি বোঝার জন্য এটির বাগগুলি সনাক্ত এবং এটি ঠিক করার জন্য আরও উপযুক্ত।
চার্লস ডাফি
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.