많은 수의 파일에 대한 빠른 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(). 하지만 물론 모두의 lsfind호출 stat()특정 옵션은 같은 사용하는 경우 ls -lfind -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함수 자체는 실제로 오류를보고하지 않습니다. 정말 실패 할 수있는 유일한 전화는 opendirstat(당신이 운이 아니며 시스템이있는 경우 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답변 과 관련하여 statlstat로 변경 하고 버퍼 오버플로를 피하기 위해 경계 검사를 추가하는 것이 좋습니다 .

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.