디렉토리의 파일 수를 계산하는 가장 좋은 방법은 무엇입니까?


11

ls펑키 한 문자 (공백 \n,, ...)를 깨뜨릴 수 있기 때문에 출력을 구문 분석하는 것이 위험한 경우 디렉토리의 파일 수를 아는 가장 좋은 방법은 무엇입니까?

나는 보통 find이 파싱을 피하기 위해 의존 하지만, 마찬가지로 find mydir | wc -l같은 이유로 깨질 것입니다.

나는 지금 Solaris에서 일하고 있지만 가능한 한 다른 유니스와 다른 쉘에서 이식 가능한 답변을 찾고 있습니다.


3
복제본인지 확실하지 않습니다. 누락 된 것이 있습니까?
rahmu

1
이것은 중복 될 수 있지만 표시된 질문과는 다릅니다. find파일의 수를 재귀 적으로 가져옵니다 ( -maxdepth 1원치 않는 경우에 사용) . find mydir -maxdepth 1 -type f -printf \\n | wc -l파일 이름의 특수 문자는 처음에 인쇄되지 않으므로 특수 문자를 처리해야합니다.
Anthon

답변:


16

이 트릭은 어떻습니까?

find . -maxdepth 1 -exec echo \; | wc -l

휴대용로 find하고 wc.


5
작동하지 않습니다 ( n+1데비안 시스템에 파일을 표시 합니다). 또한 일반 파일을 필터링하지 않습니다.
Chris Down

4
방금 일반적인 예를 들었습니다. 이 작업을 수행하지만, 어떻게 작동하는 것은 당신이 적응 방법에 따라 find사용자의 특정 요구에 명령을. 예, .여기에는를 포함한 모든 디렉토리가 포함됩니다 (결과가로 표시되는 이유 일 수 있음 n+1).
rozcietrzewiacz

나는이 기술을 매우 영리합니다. 하지만 그렇게 할 수있는 간단한 방법이 없다는 것에 놀랐습니다!
rahmu

3
@ChrisDown OP는 일반 파일에 대한 필터링을 지정하지 않고 디렉토리의 파일 수를 요청합니다. n + 1 문제를 제거하려면 find . -maxdepth 1 ! -name . -exec echo \; | wc -l; 일부 이전 버전에는 find없습니다 -not.
Arcege

3
참고 -maxdepth표준되지 않습니다 (지금 또한 몇 가지 다른 구현에서 지원하는 GNU 확장).
Stéphane Chazelas

11

외부 유틸리티없이 루프를 사용하거나 루프를 사용하지 마십시오.

shopt -s dotglob
files=(*)
echo ${#files[@]}

KSH에서 교체 shopt -s dotglobFIGNORE=.?(.). zsh에서로 바꾸 setopt glob_dots거나 shopt통화를 제거 하고을 사용하십시오 files=(*(D)). 또는 도트 파일을 포함하지 않으려면 그냥 줄을 삭제하십시오. 점 파일에 관심이없는 경우 :

set -- *
echo $#

도트 파일을 포함하려면 다음을 수행하십시오.

set -- *
if [ -e "$1" ]; then c=$#; else c=0; fi
set .[!.]*
if [ -e "$1" ]; then c=$((c+$#)); fi
set ..?*
if [ -e "$1" ]; then c=$((c+$#)); fi
echo $c

2
첫 번째 예 는 활성화되지 않은 1경우 빈 디렉토리 를 인쇄 합니다 nullglob. zsh a=(*(DN));echo ${#a}에서 N( nullglob) 한정자를 사용하면 빈 디렉토리에 오류가 발생하지 않습니다.
nisetama

8
find . ! -name . -prune -print | grep -c /

80 년대 이후 시스템에 이식성이 뛰어나야합니다.

모든 디렉토리 항목을 제외한 카운트 그 ...현재 디렉토리이다.

서브 디렉토리의 파일도 계산하려면 다음을 수행하십시오.

find .//. ! -name . | grep -c //

(필요하지 않기 때문에 Unix V6 (1975)에도 이식 가능해야 함 -prune)


이 페이지에서 드문 휴대용 답변 중 하나입니다.
xhienne

어제이 대답은 현재 디렉토리 ( find dirname ! -name dirname -prune -print) 이외의 디렉토리에서도 잘 작동한다는 것을 알았습니다 . 그 이후로 (계산에 더 일반적으로 사용되는) grep -c /대신 사용해야 할 특별한 이유가 있는지 궁금합니다 wc -l.
Anthony Geoghegan

1
find dirname ! -name dirname그 안에 다른 디렉토리가 있으면 작동하지 않습니다 dirname. 를 사용하는 것이 좋습니다 find dirname/. ! -name .. wc -l줄 수를 세고, 줄 바꿈 문자가 파일 이름에서와 같이 유효하므로 파일 이름을 여러 줄로 만들 수 있습니다.
Stéphane Chazelas

6

시험:

ls -b1A | wc -l

-b인쇄 할 수없는 문자를 가지며 , 및 -A파일을 제외한 모든 파일을 표시합니다 (파이프의 기본값이지만 명시 적으로 좋습니다)....

우리가 더 높은 수준의 스크립팅 언어를 포함하는 한, 파이썬에서 한 줄짜리가 있습니다.

python -c 'import os; print len(os.listdir(os.sep))'

또는 완전한 '찾기'가있는 경우 :

python -c 'import os; print len([j for i in os.walk(os.sep) for j in i[1]+i[2]])'

1

Yoc는 이러한 구성을 사용할 수 있습니다.

I=0; for i in * ; do ((I++)); done ; echo $I

그러나 Argument list too long.디렉토리에 파일이 너무 많은 경우 와 같이 오류 가 발생할 수 있습니다. 그러나 100 억 개의 파일이있는 디렉토리에서 테스트했으며 잘 작동했습니다.


3
쉘이 파일을 확장하도록 구성되어 있지 않으면 숨겨진 파일에 대해서는 작동하지 않습니다 *.
Lekensteyn

gnu find . -maxdepth 1 -type f | wc -l
Nikhil Mulley

4
@Rush :이 명령은 "arg list를 너무 길게"올릴 수 없습니다. 즉에서만 때문에 결코 (외부 명령으로 일어나지 않는다 for.
enzotib

1

상대적으로 이식성이 좋은 펄을 고려 했습니까?

다음과 같은 것 :

use File::Find;

$counter = 0;

sub wanted { 
  -f && ++$counter
}

find(\&wanted, @directories_to_search);
print "$counter\n";

0

이것을 => -i (노드 번호의 경우) 및 -F ( '/'와 함께 디렉토리 이름 추가) 옵션과 함께 ls 사용하십시오 .

ls -ilF | egrep -v '/' | wc -l

0

A의 perl한줄 (가독성 포맷) :

perl -e 'opendir($dh, ".");
         while ( readdir($dh) ) {$count++};
         closedir $dh;
         print "$count\n";'

또는

perl -e 'opendir($dh, ".");
         @files = readdir($dh);
         closedir $dh;
         print $#files+1,"\n";'

두 번째 버전과 perl같이 grep또는 map두 번째 버전으로 배열을 수정 하는 함수를 사용할 수 있습니다 . perldoc -f readdir를 사용하는 예를 참조하십시오 grep.


0

내가 항상 사용하고 문제가 없었던 가장 간단한 버전은 다음과 같습니다. ls -b1 | wc -l


파일 이름에 \n다른 펑키 문자 가 포함되어 있으면 문제가 발생할 수 있습니다 (예 : 특정 유니스에서 허용).
rahmu

1
답변을 게시하기 전에 명시 적으로 시도했지만 아무런 문제가 없었습니다. 노틸러스 파일 관리자를 사용하여 \ n을 포함하도록 파일 이름을 바꾸어 시도했습니다.
피터

당신은 그렇습니다. 그렇게 작동하지 않습니다. 나는 이것을 처음 테스트했을 때 내가 한 일을 모른다. 다시 시도하고 내 대답을 업데이트했습니다.
피터

아니요, 명령은 정상이지만 이미 유사한 솔루션이 있으며 숨겨진 파일은 계산되지 않습니다.
xhienne

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.