디렉터리에 있는 파일 수를 계산하는 가장 리소스 효율적인 방법은 무엇입니까?

디렉터리에 있는 파일 수를 계산하는 가장 리소스 효율적인 방법은 무엇입니까?

센트OS 5.9

요전에 디렉토리에 많은 파일이 있는 문제에 부딪혔습니다. 계산하기 위해 나는 달렸다ls -l /foo/foo2/ | wc -l

단일 디렉터리에 100만 개 이상의 파일이 있는 것으로 나타났습니다(긴 이야기 - 근본 원인이 해결되고 있음).

내 질문은: 계산을 수행하는 더 빠른 방법이 있습니까? 카운트를 얻는 가장 효율적인 방법은 무엇입니까?

답변1

짧은 답변:

\ls -afq | wc -l

(여기에는 .합계가 포함되어 있으므로 ..2를 뺍니다.)


디렉터리의 파일을 나열하면 세 가지 일반적인 상황이 발생할 수 있습니다.

  1. 디렉터리의 파일 이름을 열거합니다. 이는 피할 수 없는 일입니다. 파일을 열거하지 않고는 디렉터리에 있는 파일의 수를 셀 수 없습니다.
  2. 파일 이름을 정렬합니다. 쉘 와일드카드와 ls명령을 사용하여 이를 수행할 수 있습니다.
  3. 부르다stat디렉터리인지 여부 등 각 디렉터리 항목에 대한 메타데이터를 검색합니다.

#3은 각 파일에 대해 inode를 로드해야 하므로 비용이 가장 많이 듭니다. 대조적으로, #1에 필요한 모든 파일 이름은 몇 개의 블록에 콤팩트하게 저장됩니다. #2는 약간의 CPU 시간을 낭비하지만 일반적으로 거래 중단 요인은 아닙니다.

파일 이름에 개행 문자가 없으면 단순히 ls -A | wc -l디렉터리에 파일이 몇 개 있는지 알려줍니다. 별칭이 있는 경우 ls호출이 트리거될 수 있으므로 stat(예: 호출이 필요한 ls --color파일 ls -F형식을 알아야 함 stat) 명령줄에서 호출하거나 command ls -A | wc -l별칭 \ls -A | wc -l을 피하세요.

파일 이름에 줄바꿈이 있는 경우 줄바꿈 나열 여부는 Unix 변형에 따라 다릅니다. GNU coreutils 및 BusyBox는 ?기본적으로 개행을 표시하므로 안전합니다.

ls -f항목을 정렬하지 않고 나열하기 위해 호출됩니다 (#2). 이는 자동으로 켜집니다 -a(적어도 최신 시스템에서는). 이 -f옵션은 POSIX에 있지만 선택적 상태입니다. 대부분의 구현에서는 이를 지원하지만 BusyBox는 지원하지 않습니다. 이 옵션은 -q인쇄할 수 없는 문자(줄 바꿈 포함)를 로 대체합니다 ?. 이는 POSIX이지만 BusyBox에서는 지원되지 않습니다. 따라서 BusyBox 지원이 필요한 경우 이름에 줄 바꿈이 포함된 파일 수를 희생하여 무시하십시오.

디렉토리에 하위 디렉토리가 없으면 대부분의 버전은 해당 항목을 find호출하지 않습니다 stat(리프 디렉토리 최적화: 링크 수가 2인 디렉토리는 하위 디렉토리를 가질 수 없으므로 find조건에서 요구하지 않는 한 항목의 메타데이터를 조회할 필요가 없습니다 -type). 이는 find . | wc -l디렉터리에 하위 디렉터리가 없고 파일 이름에 개행 문자가 포함되지 않은 경우 디렉터리의 파일 수를 계산하는 이식 가능하고 빠른 방법입니다.

디렉터리에 하위 디렉터리가 없지만 파일 이름에 개행 문자가 포함될 수 있는 경우 다음 중 하나를 시도해 보십시오. 지원되는 경우 두 번째 디렉터리가 더 빠르지만 눈에 띄게 그렇지 않을 수도 있습니다.

find -print0 | tr -dc \\0 | wc -c
find -printf a | wc -c

반면, find디렉토리에 하위 디렉토리가 있는 경우 :을 사용하지 마십시오. 또는 각 항목을 find . -maxdepth 1호출할 수도 있습니다 stat(적어도 GNU 찾기 및 BusyBox 찾기 사용). 정렬(#2)을 피할 수 있지만 inode 조회(#3)가 발생하여 성능이 저하됩니다.

외부 도구가 없는 셸에서는 .run을 사용하여 현재 디렉터리의 파일 수를 계산할 수 있습니다 set -- *; echo $#. 이는 도트 파일(이름이 로 시작하는 파일 .)을 놓치고 빈 디렉토리에 0 대신 1을 보고합니다. 이는 외부 프로그램을 시작할 필요가 없기 때문에 작은 디렉터리의 파일 수를 계산하는 가장 빠른 방법이지만(zsh 제외) 정렬 단계(#2)로 인해 더 큰 디렉터리에 시간을 낭비합니다.

  • Bash에서 이는 현재 디렉터리의 파일 수를 계산하는 안정적인 방법입니다.

    shopt -s dotglob nullglob
    a=(*)
    echo ${#a[@]}
    
  • ksh93에서 이는 현재 디렉터리의 파일 수를 계산하는 안정적인 방법입니다.

    FIGNORE='@(.|..)'
    a=(~(N)*)
    echo ${#a[@]}
    
  • zsh에서 이는 현재 디렉터리의 파일 수를 계산하는 안정적인 방법입니다.

    a=(*(DNoN))
    echo $#a
    

    이 옵션을 설정 한 경우 mark_dirs해당 옵션을 꺼야 합니다. a=(*(DNoN^M)).

  • 모든 POSIX 셸에서 이는 현재 디렉터리의 파일 수를 계산하는 안정적인 방법입니다.

    total=0
    set -- *
    if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
    set -- .[!.]*
    if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
    set -- ..?*
    if [ $# -ne 1 ] || [ -e "$1" ] || [ -L "$1" ]; then total=$((total+$#)); fi
    echo "$total"
    

zsh를 제외하고 이러한 모든 방법은 파일 이름을 정렬합니다.

답변2

find /foo/foo2/ -maxdepth 1 | wc -l

내 컴퓨터에서는 훨씬 빠르지만 로컬 .디렉터리가 개수에 추가됩니다.

답변3

ls -1U파이프라인은 파일 항목을 정렬하려고 시도하지 않고 디스크의 폴더에 정렬된 대로 읽기만 하므로 리소스 비용이 적게 듭니다. 또한 출력이 적습니다. 즉 wc, .

ls -fwhich is more 또는 less 를 사용할 수도 있습니다 ls -1aU.

파이핑 없이 명령을 통해 이를 수행하는 자원 효율적인 방법이 있는지 모르겠습니다.

답변4

당신은 시도 할 수 있습니다perl -e 'opendir($dh,".");$i=0;while(readdir $dh){$i++};print "$i\n";'

쉘 파이프와 시간을 비교하는 것은 흥미로울 것입니다.

관련 정보