많은 수의 파일에 대한 빠른 Linux 파일 수


136

파일 수가 매우 많을 때 (> 100,000) 특정 디렉토리에서 파일 수를 찾는 가장 좋은 방법을 찾으려고합니다.

파일이 많으면 ls | wc -l실행하는 데 시간이 오래 걸립니다. 나는 이것이 모든 파일의 이름을 반환하기 때문이라고 생각합니다. 가능한 한 적은 디스크 IO를 사용하려고합니다.

나는 쓸데없는 쉘과 Perl 스크립트를 실험했다. 어떤 아이디어?


2
"ls"가 / usr / bin / ls이고 다른 것의 별칭이 아닌지 확인하십시오.
— glenn jackman

: 여기에 흥미로운 답변 비슷한 질문 serverfault.com/questions/205071/...
— 에이단

이 질문에 제시된 모든 솔루션이 Linux 에만 국한된 것은 아니지만 모든 * NIX 계열 시스템에 대해 일반적으로 적용 된다는 점을 지적 할 가치가 있습니다. "Linux"태그를 제거하는 것이 좋습니다.
— Christopher Schultz

답변:


188

기본적으로 ls이름이 정렬되며 이름이 많으면 시간이 걸릴 수 있습니다. 또한 모든 이름을 읽고 정렬 할 때까지 출력이 없습니다. ls -f정렬을 끄 려면이 옵션을 사용하십시오 .

ls -f | wc -l

참고이 또한 가능하게됩니다 -a, 그래서 ., ..로 시작 및 기타 파일 .계산됩니다.


11
+1 그리고 나는 알아야 할 모든 것을 알고 있다고 생각했습니다 ls.
— mob

5
ZOMG. 100K 라인의 정렬은 아무것도 아닙니다 . 모든 파일 에서 stat()호출하는 것과 비교할 ls때. 따라서 더 빨리 작동 find하지 않습니다 stat().
— Dummy00001

12
ls -f하지 않습니다 stat(). 하지만 물론 모두의 ls및 find호출 stat()특정 옵션은 같은 사용하는 경우 ls -l나 find -mtime.
— mark4o

7
문맥 상, 작은 Slicehost 상자에서 250 만 jpg를 계산하는 데 1-2 분이 걸렸습니다.
— philfreo

6
카운트에 하위 디렉토리를 추가하려면 다음을 수행하십시오.ls -fR | wc -l
— Ryan Walls

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 회씩 각각 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 비트 리눅스에서 그것을 테스트,하지만 해야 Microsoft Windows를 포함한 모든 POSIX 호환 시스템에서 작동 합니다. 버그 리포트는 환영합니다; AIX 또는 OS / 400 등에서 작동하지 않는 경우이를 업데이트하게되어 기쁩니다.

보시다시피, 그것은 원래보다 훨씬 복잡하며 반드시 그렇게해야합니다. 코드가 매우 복잡해지기를 원하지 않는 한 (예 : 하위 디렉토리 스택 관리 및 단일 루프에서 처리) 적어도 하나의 함수가 재귀 적으로 호출되어야합니다. 파일 형식을 확인해야하므로 다른 OS, 표준 라이브러리 등의 차이가 발생하기 때문에 컴파일 할 모든 시스템에서 사용할 수있는 프로그램을 작성했습니다.

오류 검사는 거의 없으며 count함수 자체는 실제로 오류를보고하지 않습니다. 정말 실패 할 수있는 유일한 전화는 opendir와 stat(당신이 운이 아니며 시스템이있는 경우 dirent파일 형식이 이미 포함되어 있습니다)를. 하위 디렉토리 경로 이름의 전체 길이를 확인하는 것에 대해 편집증이 아니지만 이론적으로 시스템은보다 긴 경로 이름을 허용해서는 안됩니다 PATH_MAX. 우려 사항이 있으면 수정할 수는 있지만 C 작성을 배우는 사람에게 설명해야 할 코드가 더 많습니다.이 프로그램은 하위 디렉토리로 재귀 적으로 다이빙하는 방법의 예입니다.

#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 수정

@FlyingCodeMonkey가 제안한 두 가지 변경 사항을 통합했습니다.

  1. lstat대신에 사용하십시오 stat. 스캔하는 디렉토리에 심볼릭 링크 된 디렉토리가있는 경우 프로그램의 동작이 변경됩니다. 이전의 동작은 (링크 된) 서브 디렉토리가 파일 수를 전체 수에 추가 한 것입니다. 새로운 동작은 연결된 디렉토리가 단일 파일로 계산되고 그 내용은 계산되지 않는다는 것입니다.
  2. 파일 경로가 너무 길면 오류 메시지가 표시되고 프로그램이 중지됩니다.

2017-06-29 편집

운이 좋으면 이것은이 답변 의 마지막 편집 일 것입니다 :)

이 코드를 GitHub 리포지토리 에 복사하여 복사 / 붙여 넣기 대신 소스를 다운로드하는 대신 코드를 좀 더 쉽게 얻을 수 있도록 만들었습니다. GitHub에서 요청합니다.

소스는 Apache License 2.0에 따라 사용 가능합니다. 패치 * 환영합니다!


  • "패치"는 저 같은 노인들이 "풀 요청"이라고 부르는 것입니다.

2
그냥 대단해! 감사! 그리고 알지 못하는 사람들을 위해 : 당신은 터미널에서 위의 코드를 준수 할 수 있습니다 : gcc -o dircnt dircnt.c사용은 다음과 같습니다./dircnt some_dir
— aesede

이것을 재귀 적으로 만드는 쉬운 방법이 있습니까?
— ck_

@ck_ 물론, 이것은 재귀 적으로 쉽게 만들 수 있습니다. 솔루션에 대한 도움이 필요합니까, 아니면 모든 것을 쓰도록 하시겠습니까?
— Christopher Schultz

1
@ChristopherSchultz, 위에 게시 한 벤치 마크-문제의 디렉토리가 얼마나 컸습니까?
— Dom Vinyard

1
파이썬에서 이것을 사용하고 싶었으므로 ffcount 패키지로 패키지했습니다. @ChristopherSchultz에서 코드를 사용할 수있게 해주셔서 감사합니다!
— GjjvdBurg

35

찾았 어? 예를 들면 다음과 같습니다.

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

1
현재 디렉토리에서 파일 을 재귀 적으로 찾습니다.
— mark4o

내 시스템에서 find /usr/share | wc -l(~ 137,000 파일)은 ls -R /usr/share | wc -l각각의 첫 번째 실행에서 (dir 이름, dir total 및 blank 행을 포함하여 ~ 160,000 줄) 보다 약 25 % 빠르며 후속 (캐시 된) 실행을 비교할 때 적어도 두 배 빠릅니다.
— 추후 공지가있을 때까지 일시 중지되었습니다.

11
전체 트리가 아닌 현재 디렉토리 만 원하는 경우 -maxdepth 1 옵션을 추가하여 찾을 수 있습니다.
— igustin

3
사용 방법으로 인해 이유 find가 더 빠릅니다 . 정렬을 중지 하고 비슷한 성능을 가진 경우 lslslsfind
— Christopher Schultz

17

ls와 perl은 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

그리고 perl opendir / readdir과 동시에 :

[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

참고 : 나는 빈은 / LS 별칭 옵션 바이 패스 확인하기 위해 -f / 사용 할 수 조금 느리게하고 -f 파일 순서를 피하기 위해. -f가없는 ls는 ls가 -f와 함께 사용되는 경우를 제외하고는 find / perl보다 두 배 느립니다. 같은 시간 인 것 같습니다.

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

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

또한 모든 불필요한 정보없이 파일 시스템을 직접 요청하는 스크립트를 갖고 싶습니다.

Peter van der Heijden, glenn jackman 및 mark4o의 답변을 기반으로 한 테스트.

도마


5
테스트 사이의 캐시를 확실히 지워야합니다. ls -l | wc -l1M 파일이있는 외부 2.5 "HDD의 폴더에서 처음 실행 하는 경우 작업을 완료하는 데 약 3 분이 소요됩니다. 두 번째는 IIRC 12 초가 소요됩니다. 또한 파일 시스템에 따라 달라질 수 있습니다. 사용하고 있었다 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
— Pažout

5

요구 사항에 따라 출력을 변경할 수 있지만 다음은 숫자로 명명 된 일련의 디렉토리에있는 파일 수를 재귀 적으로 계산하고보고하기 위해 작성한 bash one-liner입니다.

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

지정된 디렉토리의 모든 파일 (디렉토리가 아닌)을 재귀 적으로 찾고 결과를 해시와 같은 형식으로 리턴합니다. find 명령을 간단히 조정하면 어떤 종류의 파일을 더 구체적으로 계산할 수 있습니까?

다음과 같은 결과가 나타납니다.

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

1
예제가 약간 혼란 스러웠습니다. 디렉토리 이름 대신 왼쪽에 왜 숫자가 있는지 궁금합니다. 그래도 고마워요, 약간의 미세 조정으로 사용했습니다. (디렉토리를 세고 기본 폴더 이름을 $ (ls -1. | sort -n)에서 i로 삭제합니다.; {echo "$ i => $ (find $ {i} | wc -l)";}
— TheJacobTaylor

왼쪽의 숫자는 예제 데이터의 디렉토리 이름입니다. 혼란스러워서 죄송합니다.
— mightybs

1
ls -1 ${dir}더 많은 공간이 없으면 제대로 작동하지 않습니다. 또한,에 의해 반환 된 이름을한다는 보장이 없다 ls에 전달 될 수있는 find바와 같이, ls인간의 소비에 대한 이스케이프 인쇄 할 수없는 문자는. ( mkdir $'oddly\nnamed\ndirectory'특히 흥미로운 테스트 사례를 원한다면). ls (1)의 출력을 구문 분석하지 말아야하는 이유를
— Charles Duffy

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. 참고로 내 컴퓨터에서 트리가 내 전체 디렉토리를 계산하는 데 4.8 초가 걸렸습니다. find -type f | wc -l5.3 초가 걸리고 0.5 초가 더 걸렸습니다. 그래서 저는 나무가 속도면에서 상당히 경쟁력이 있다고 생각합니다.

하위 폴더가없는 한 트리는 파일을 계산하는 빠르고 쉬운 방법입니다.

또한 재미있게도 tree | grep '^├'현재 디렉토리의 파일 / 폴더 만 표시 할 수 있습니다 -이것은 기본적으로 훨씬 느린 버전입니다 ls.


Brew install tailOS X 용
— Unfun Cat

@TheUnfunCat tail이 Mac OS X 시스템에 이미 설치되어 있어야합니다.
— Christopher Schultz

4

빠른 Linux 파일 수

내가 아는 가장 빠른 리눅스 파일 수는

locate -c -r '/home'

grep을 호출 할 필요 가 없습니다 ! 그러나 언급했듯이 새로운 데이터베이스 (크론 작업으로 매일 업데이트되거나 수동으로 업데이트)가 있어야합니다 sudo updatedb.

에서 사람의 위치

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

또한 디렉토리도 파일로 계산한다는 것을 알아야합니다!


BTW : 시스템 유형의 파일 및 디렉토리에 대한 개요를 원하는 경우

locate -S

디렉토리, 파일 수 등을 출력합니다.


데이터베이스가 최신인지 확인해야합니다.
— phuclv

1
LOL 데이터베이스에 모든 수를 이미 가지고 있다면 확실히 빠르게 계산할 수 있습니다. :)
— Christopher Schultz

3

나는 충분한 명성 포인트가없는 여기이 작성 주석 대답에,하지만 난 할 수 있어요 내 자신의 떠나 이해가되지 않습니다 대답을. 어쨌든...

Christopher Schultz 의 답변 과 관련하여 stat 를 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좋은 제안이었고, 당신은 그것을 위해 업장을받을 자격이 있기 때문에 모딩 . 이 제안은 위에 게시 된 코드와 GitHub에 통합되었습니다.
— Christopher Schultz


2

이 대답은 매우 크고 중첩 된 디렉토리의 경우이 페이지의 다른 모든 것보다 빠릅니다.

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

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


1
좋은. 모든 파일에 대한 최신 db가 이미 있으므로 다시 시작할 필요가 없습니다. 그러나 안타깝게도 updatedb 명령이이 메소드에 대해 이미 실행되어 완료되었는지 확인해야합니다.
— Chris Reid

당신은 grep 필요가 없습니다. abu_bua의 솔루션locate -c -r '/path'
— phuclv

2

~ 10K 파일로 ~ 10K 폴더의 데이터 세트에서 파일을 계산하려고 할 때 여기에 왔습니다. 많은 접근 방식의 문제점은 100M 파일을 암시 적으로 스 태팅한다는 점입니다.

나는 christopher-schultz의 접근 방식을 자유롭게 확장 하여 args를 통해 디렉토리를 전달하는 것을 지원했습니다 (재귀 적 접근 방식은 stat도 사용합니다).

다음을 파일에 넣으십시오 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/*

10K 폴더의 100M 파일에서 위의 작업은 매우 빠르게 완료됩니다 (처음 실행시 ~ 5 분, 캐시에서 추적 : ~ 23 초).

1 시간 이내에 완료된 유일한 다른 접근 방식은 캐시에서 약 1 분 동안의 ls였습니다 ls -f /your/dirs/* | wc -l. dir 당 몇 줄의 줄 바꿈으로 카운트가 사라졌습니다 ...

예상 find한 시간 이외에, 한 번도 내 시도가 전혀 없었습니다 :-/


C 프로그래머가 아닌 누군가에게 왜 이것이 더 빠를 지, 어떻게 똑같은 일을하지 않고 어떻게 같은 대답을 얻을 수 있는지 설명 할 수 있습니까?
— mlissner

C 프로그래머 일 필요는 없습니다. 파일을 스 태팅하는 것이 무엇을 의미하고 디렉토리가 어떻게 표시되는지 이해하면됩니다. 디렉토리는 기본적으로 파일 이름과 inode 목록입니다. 파일을 지정하면 드라이브의 어딘가에있는 inode에 액세스하여 파일 크기, 권한 등의 정보를 얻을 수 있습니다. 디렉토리 당 카운트에 관심이 있다면 inode 정보에 액세스 할 필요가 없으므로 많은 시간을 절약 할 수 있습니다.
— Jörn Hees

Oracle Linux, gcc 버전 4.8.5 20150623 (Red Hat 4.8.5-28.0.1) (GCC)에서이 segfaults ... 상대 경로 및 원격 fs가 원인 인 것 같습니다
— Rondo

2

리눅스에서 가장 빠른 방법 (질문은 리눅스로 태그 지정됨)은 직접 시스템 호출을 사용하는 것입니다. 다음은 디렉토리의 파일 만 계산하고 (디어 없음) 작은 프로그램입니다. 수백만 개의 파일을 셀 수 있으며 "ls -f"보다 약 2.5 배 빠르며 Christopher Schultz의 답변보다 약 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않았지만 결국 거의 동일한 코드로 요약됩니다. 이러한 방식으로 시스템 호출을 수행하는 것도 이식성이 없으며 Linux ABI가 안정적이지 않기 때문에 한 시스템에서 컴파일 된 프로그램이 다른 시스템에서 제대로 작동하지 않을 수 있습니다 (모든 * NIX 시스템 IMO의 소스에서 컴파일하는 것이 좋습니다) ). 속도가 핵심이라면 실제로 속도를 향상시키는 경우 좋은 솔루션입니다. 프로그램을 별도로 벤치마킹하지 않았습니다.
— Christopher Schultz

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와 디렉토리를 나열하는 다른 모든 방법 (python os.listdir, find 포함)은 libc readdir ()에 의존합니다. 그러나 readdir ()은 한 번에 32K의 디렉토리 항목 만 읽습니다. 즉, 같은 디렉토리에 많은 파일이있는 경우 (즉, 500M의 디렉토리 항목) 모든 디렉토리 항목을 읽는 데 시간이 오래 걸립니다. 특히 느린 디스크에서. 많은 수의 파일이 포함 된 디렉토리의 경우 readdir ()에 의존하는 도구보다 더 깊이 파고 들어야합니다. libc의 헬퍼 메소드보다는 getdents () syscall을 직접 사용해야합니다.

getdents ()를 사용하여 파일을 나열하는 C 코드를 여기 에서 찾을 수 있습니다 .

디렉토리의 모든 파일을 빠르게 나열하려면 두 가지 수정이 필요합니다.

먼저 버퍼 크기를 X에서 5MB로 늘리십시오.

#define BUF_SIZE 1024*1024*5

그런 다음 inode == 0으로 항목을 건너 뛰기 위해 디렉토리의 각 파일에 대한 정보를 인쇄하는 기본 루프를 수정하십시오.

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

내 경우에는 디렉토리의 파일 이름 만 신경 쓰므로 파일 이름 만 인쇄하도록 printf () 문을 다시 작성했습니다.

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

컴파일하십시오 (외부 라이브러리가 필요하지 않으므로 매우 간단합니다)

gcc listdir.c -o listdir

이제 그냥 실행

./listdir [directory with insane number of files]

Linux는 미리 읽기를 수행하므로 readdir()실제로 느리지는 않습니다. 이 성능 향상을 위해 이식성을 버릴 가치가 있다고 생각하기 전에 확실한 그림이 필요합니다.
— fuz

-1

디렉토리의 파일 수 변경 사항을 추적하려면 다음 명령을 선호합니다.

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

이 명령은 0.1 초의 새로 고침 빈도로 디렉토리에있는 파일 수를 추적하기 위해 창을 열어 둡니다.


당신은 그 확신 ls | wc -l0.01 초에있는 파일의 수천 또는 수백만 폴더를 완료됩니다? 심지어 ls다른 솔루션에 비해 상당히 비효율적이다. 그리고 OP는 단지 출력 변화를보고 앉아 있지 않고 카운트를 원합니다
— phuclv

잘. 잘. 나는 나에게 맞는 우아한 해결책을 찾았다. 나는 같은 것을 공유하고 싶었다. 나는 리눅스에서 'ls'명령이 매우 비효율적이라는 것을 모른다. 그 대신에 무엇을 사용하고 있습니까? 그리고 0.01은 새로 고침 빈도입니다. 시간이 아냐 watch를 사용하지 않았다면 맨 페이지를 참조하십시오.
— Anoop Toffy

글쎄, 나는 watch그 주석 후에 매뉴얼을 읽었으며 대부분의 PC 화면의 화면 주사율이 60Hz에 불과하기 때문에 0.01 (0.1s 아님)이 비현실적이라는 것을 알았습니다 . OP는 "많은 파일에 대한 빠른 Linux 파일 수"에 대해 물었습니다. 게시하기 전에 사용 가능한 답변을 읽지 않았습니다
— phuclv

나는 답을 읽었습니다. 그러나 내가 게시 한 것은 디렉토리의 파일 수 변경을 추적하는 방법입니다. 예를 들어, 한 위치에서 다른 위치로 파일을 복사하는 동안 파일 수는 변경 사항을 유지합니다. 방법 I 포스터를 사용하면이를 추적 할 수 있습니다. 내가 게시 한 게시물은 이전 게시물을 수정하거나 개선하지 않습니다.
— Anoop Toffy

-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
이것은 mightybs가 작성한 ( 동일한 버그로) 답변과 놀랍게도 비슷합니다 . 다른 사람이 작성한 코드를 확장하거나 수정하려는 경우 코드를 작성하는 것이 적절합니다. 답변에서 버그를 식별하고 수정하기에 충분한 코드를 이해하는 것이 훨씬 더 적합합니다.
— Charles Duffy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.