파일 수가 많은 디렉토리에서는 ls 명령이 작동하지 않습니다


70

5 백만 개의 파일 이있는 디렉토리가있었습니다 . ls이 디렉토리 내에서 명령 을 실행하려고 할 때 시스템이 엄청난 양의 메모리를 소비했으며 언젠가는 중단되었습니다. ls명령을 사용하지 않고 파일을 나열하는 효율적인 방법이 있습니까?


11
당신이 별칭이없는 있는지 확인 ls하는 사용 --color또는 -F그와 같은 일을 의미 lstat(2)각 파일에 대해.
Stéphane Chazelas

4
그런데 단일 디렉토리에 수백만 개의 파일을 저장하는 것은 다소 나쁜 생각입니다. 디렉토리 레이아웃을 제어하는 ​​경우 일부 기준으로 분할 할 수 있습니까?
d33tah

그게 순수한 ls전화입니까 아니면 옵션을 사용 했습니까?
Hauke ​​Laging

1
@ d33tah 그래, 5 백만이 많다! 루트 파일 시스템은 7 백만 inode로 제한됩니다.
Mikel

7
출력 할 5 백만 개의 항목-어떻게 보십니까-간단한 리스팅이 너무 많이 보임-목록에 무엇을 원하십니까?
user151019

답변:


66

다음을 사용하여 정렬하지 마십시오.

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

또는 동등하게 :

ls -U

10
열 레이아웃이 얼마나 많은 오버 헤드를 추가하는지 궁금합니다. -1깃발을 추가하면 도움이 될 수 있습니다.
Mikel

아마 별로는 아니지만 모든 도움이 될 것입니다. :)
Mikel

1
@Mikel 그게 추측일까요, 아니면 측정 했습니까? 나에게는 -1더 오래 걸리는 것 같습니다 .
Hauke ​​Laging

10
"-1"은 상당히 도움이됩니다. "ls -f -1"은 통계 호출을 피하고 모든 것을 즉시 인쇄합니다. 열 출력 (터미널로 보낼 때 기본값)은 모든 것을 먼저 버퍼링합니다. 내 시스템에서 8 백만 개의 파일 ( "seq 1 8000000 | xargs touch"로 생성 된 파일)이있는 디렉토리에서 btrfs를 사용하면 "time ls -f -1 | wc -l"은 5 초 미만인 반면 "time ls -f -C | wc -l "은 30 초 이상 걸립니다.
Scott Lamb

1
@ToolmakerSteve 기본 동작 ( -Cstdout이 터미널 인 -1경우 파이프 인 경우)이 혼동됩니다. 실험하고 측정 할 때는 출력을보고 (명령이 예상 한대로 작동하는지 확인) 억제하는 것 (터미널 응용 프로그램 처리량의 혼란 요소를 피하기 위해) 사이를 전환합니다. 더 나은 그렇게 명시를 통해 출력 형식을 정의, 두 모드에서 동일한 방식으로 동작 명령을 사용 -1, -C, -l, 등
스콧 어린 양

47

ls실제로 파일을 정렬하고 디렉토리에 백만 개가 넘는 파일을 나열하려고하면 파일을 나열하려고합니다. 링크 에서 언급했듯이 strace또는 find파일을 사용 하거나 나열 할 수 있습니다. 그러나 5 백만 개의 파일이 있기 때문에 이러한 옵션도 내 문제에 적합하지 않은 것으로 보입니다. 인터넷 검색의 일부 비트 후, 나는 우리가 사용하는 디렉토리를 게시하면 발견 getdents()하기 때문에, 빠른 있어야하는데 ls, findPython라이브러리를 사용 readdir()느리지 만 사용하는 getdents()아래.

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

/*
 * 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

타이밍 예 : 시스템 구성에 따라 getdents보다 빠를 수 있습니다 ls -f. 다음은 컴퓨팅 클러스터의 NFS 마운트를 통해 약 500k 파일을 포함하는 디렉토리를 나열하는 데 40 배 속도가 향상된 것을 보여주는 몇 가지 타이밍입니다. 각 명령은 즉시 연속해서 10 번 실행 된 getdents다음에 ls -f. 첫 번째 실행은 NFS 캐싱 페이지 결함으로 인해 다른 모든 것보다 상당히 느립니다. (제외 :이 마운트를 통해 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있습니까?
Bernhard

1
단. 또한 이름을 나열하지 않고 항목 (파일)을 간단히 계산하는 옵션을 추가 할 수 있습니다 (이 목록의 경우 printf에 대한 수백만 건의 호출 저장).
ChuckCottrill

29
내용을 나열하기 위해 사용자 정의 코드를 작성해야 할 때 디렉토리가 너무 크다는 것을 알고 있습니다.
casey

1
@casey 꼭 할 필요는 없습니다. 이 이야기에 대한 모든 이야기 는 요점을 getdentsreaddir칩니다.
Mikel

9
어서! 이미 5 백만 개의 파일이 있습니다. 사용자 정의 "ls"프로그램을 다른 디렉토리에 넣으십시오.
Johan

12

속도가 느린 가장 큰 이유는 파일 유형의 색상이므로 색상 옵션을 사용 \ls하거나 /bin/ls사용 하지 않도록 설정할 수 있습니다.

실제로 디렉토리에 너무 많은 파일이 있으면 find대신 사용 하는 것이 좋습니다.


7
나는 이것이 downvoted되었을 것이라고 생각하지 않습니다. 정렬은 하나의 문제이지만 정렬하지 않더라도 각 파일을 ls -U --color처리하는 데 시간이 오래 걸립니다 stat. 그래서 둘 다 맞습니다.
Mikel

채색 기능을 끄면 성능에 큰 영향을 미치며 ls기본적으로 별명으로 표시됩니다 .bashrc.
Victor Schröder

/bin/ls -U, 아주 오랜 시간을 기다리는 것과 비교하여 시간이
지나지 않아서

-3

나는 그것이 echo *ls보다 훨씬 빨리 작동 한다는 것을 알았습니다. YMMV.


4
쉘은을 정렬합니다 *. 따라서이 방법은 5 백만 개의 파일에 대해서는 여전히 매우 느립니다.
Mikel

3
@Mikel 그 이상으로, 5 백만 개의 파일이 globbing이 완전히 중단되는 지점 이상이라고 확신합니다.
evilsoup

4
최소 파일 이름 길이 (5 백만 파일의 경우)는 3 자 (보다 일반적인 문자를 사용하는 경우 4 일 수 있음)와 파일 당 구분 기호 = 4 자 (예 : 20MB의 명령 인수)입니다. 이는 일반적인 2MB 확장 명령 줄 길이를 훨씬 초과합니다. Exec (그리고 내장)조차도 멍청 할 것입니다.
Johan
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.