디렉토리에서 파일을 계산하기 위해 wc로 파이핑하는 것보다 간결한 대안이 있습니까?


12

내가 ls -1 target_dir | wc -l하면 디렉토리에 파일 수를 얻습니다. 나는 이것을 약간 성가신 것으로 생각합니다. 더 우아하거나 간결한 방법이 있습니까?


2
화장실에 배관 할 때는 "-1"이 필요 없습니다.
Steve

ls이미 총 수를 제공하므로 어떻 ls -l | head -1습니까? 더 짧은 것을 원한다면 별명을 만드십시오.
Daniel Wagner

2
@DanielWagner "total : nnn"출력 ls -l은 파일 수가 아니라 파일의 전체 크기를 나타냅니다.
David Richerby

2
있음을 명심 ls | wc -l모든 파일 이름이 개행 문자가 포함 된 경우 당신에게 잘못된 수를 줄 것이다.
chepner

이것은 파일 시스템에 따라 다르며 디렉토리에서 디렉토리 + 2를 계산합니다. 대답에는 2 개의 추가 항목이 있습니다 (자체 계산과 부모). stat -c %h .같은 정보를 제공합니다ls -ld . | cut -d" " -f 2
CTRL-ALT-delor

답변:


12

bash 4+ (지원되는 Ubuntu 버전이 있다고 가정) :

num_files() (
    shopt -s nullglob
    cd -P -- "${1-.}" || return
    set -- *
    echo "$#"
)

로 호출하십시오 num_files [dir]. dir선택적이며, 그렇지 않으면 현재 디렉토리를 사용합니다. 원래 버전은 숨겨진 파일을 계산하지 않으므로이 두 가지도 마찬가지입니다. 당신이 그것을 원한다면, shopt -s dotglob전에 set -- *.

원래 예제는 일반 파일뿐만 아니라 디렉토리 및 기타 장치도 계산합니다. 정규 파일 (정규 파일에 대한 심볼릭 링크 포함) 만 실제로 원한다면 다음을 확인해야합니다.

num_files() (
    local count=0

    shopt -s nullglob
    cd -P -- "${1-.}" || return
    for file in *; do
        [[ -f $file ]] && let count++
    done
    echo "$count"
)

GNU find를 가지고 있다면 다음과 같은 옵션도 있습니다 (이것은 원래 명령이 수행하지 않은 숨겨진 파일을 포함합니다) :

num_files() {
    find "${1-.}" -maxdepth 1 -type f -printf x | wc -c
}

( 일반 파일에 대한 심볼릭 링크도 계산 하려면 -type로 변경 -xtype하십시오).


set파일이 매우 많더라도 실패하지 않습니까? 나는 xargs일반적인 경우에 작동하도록 몇 가지 합산 코드를 사용해야한다고 생각합니다 .
l0b0

1
또한 shopt -s dotglob시작 파일 .을 계산 하려는 경우
Digital Trauma

1
@ l0b0 set이 상황에서는 실제로 실패 하지 않을 것이라고 생각 합니다 exec. 다시 getconf ARG_MAX말해, 내 시스템에서 262144를 산출하지만 test_arg_max() { set -- {1..262145}; echo $#; }; test_arg_max, 그렇게하면 행복하게 262145에 응답합니다.
kojiro

@DavidRicherby -maxdepth는 POSIX가 아닙니다.
Chris Down

4
@MichaelMartinez 명백한 코드 작성은 올바른 코드 작성을 대신 할 수 없습니다.
Chris Down

3

f=(target_dir/*);echo ${#f[*]}

이름에 공백, 줄 바꿈 등이있는 파일에 대해 올바르게 작동합니다.


컨텍스트를 제공 할 수 있습니까? 이것은 bash 스크립트로 가야합니까?
codecowboy

할 수있었습니다. 쉘에 직접 넣을 수도 있습니다. 그 버전은 현재 디렉토리를 원한다고 가정했습니다. 귀하의 질문에 더 가깝게 편집했습니다. 기본적으로 디렉토리의 모든 파일을 포함하는 쉘 배열 변수를 작성한 다음 해당 배열의 수를 인쇄합니다. bash, ksh, zsh 등 배열이있는 모든 쉘에서 작동하지만 일반 sh / ash / dash는 아닙니다.
Aaron Davies

2

ls터미널에 직접 출력되는 경우에만 다중 열이며, "-1"옵션을 제거 할 수 있습니다. wc"-l"옵션을 제거 할 수 있으며 첫 번째 값만 읽을 수 있습니다 (게으른 솔루션, 합법적 인 증거에는 사용되지 않음, 범죄 수사, 미션 크리티컬, 전술 작전 ..).

ls target | wc 

5
줄 바꿈이 포함 된 파일 이름에는 실패합니다.
l0b0

@ Emmanuel 당신은 wc사소한 경우에도 파일 수를 얻기 위해 결과를 파싱해야 하므로 어떻게 해결책일까요?
l0b0

@Emmanuel 이것은 target확장 될 때 하이픈으로 시작하는 것들을 포함하는 glob 인 경우 실패 할 수 있습니다 . 예를 들어, 새 디렉토리를 작성하고 들어가서 수행하십시오 touch -- {1,2,3,-a}.txt && ls *|wc(NB : rm -- *.txt해당 파일을 삭제하는 데 사용 ).
David Richerby

당신은 의미 했습니까 wc -l? 그렇지 않으면 ls출력 의 줄 바꿈, 워드 및 바이트 수를 얻습니다 . David Richerby는 다음과 같이 말했습니다. 다시 분석해야합니다.
erik

@erik wc당신의 두뇌가 첫 번째 논쟁이 개행이라는 것을 알고 있다면 논란없이 논할 필요가 없습니다.
Emmanuel

2

간결함이 있다면 (이름 등의 줄 바꿈이있는 파일을 처리 할 때 정확한 정확성이 아닌) ( "line count")로 별칭 wc -l을 지정하는 것이 좋습니다 lc.

$ alias lc='wc -l'
$ ls target_dir|lc

다른 사람들이 지적했듯이 파이프에 쓸 때 자동이기 때문에 -1옵션이 필요하지 않습니다 . ( 항상 열 모드를 사용하도록 별칭을 지정 하지 않은 한 이전에는 보았지만 자주는 아닙니다.)lslsls

lc별명은 일반적으로 매우 편리합니다, 당신은 "현재 디렉토리를 계산"의 경우를 보면이 질문에 대해, ls|lc당신이 얻을 수있는 간결로에 관한 것입니다.


2

지금까지 Aaron 's는 자신보다 간결한 유일한 접근 방식입니다. 보다 정확한 접근 방식은 다음과 같습니다.

ls -aR1q | grep -Ecv '^\./|/$|^$'

이것은 인쇄 할 수없는 문자를 교체하는 데 필요한 쉘 글롭을 사용하여 현재 디렉토리 아래에 .dot 파일을 포함하여 디렉토리가 아닌 모든 파일을 한 줄에 하나씩 나열합니다. grep은 부모 디렉토리 목록이나 .. 또는 * / 또는 빈 줄을 필터링하므로 파일 당 한 줄만 있어야합니다. 그 총 개수는 grep이 반환합니다. 하위 디렉토리도 포함 시키려면 다음을 수행하십시오.

ls -aR1q | grep -Ecv '^\.{1,2}/|^$'

-R재귀 적 결과를 원하지 않으면 두 경우 모두를 제거하십시오 .


1
나는 그런 종류의 일을 선호합니다 find. 카운트 만 원한다면 다음과 같이 작동합니다. find -mindepth 1 -maxdepth 1 -printf '\n'|wc -l(깊이 컨트롤을 제거하여 재귀 적 결과를 얻으십시오).
Aaron Davies

@AaronDavies-실제로 작동하지 않습니다. 해당 파일 이름 중 하나에 개행 문자를 입력하고 직접 확인하십시오. 또한, 똑같이 할 일을하려면 : find . \! -name . -prune | wc -l-물론 작동하지 않습니다.
mikeserv

1
나는 따르지 않습니다. printf명령은 파일 이름을 전혀 포함하지 않는 상수 문자열 (줄 바꿈)을 인쇄하므로 결과는 이상한 파일 이름과 무관합니다. 이 트릭 은 물론을 find지원하지 않는으로 수행 할 수 없습니다 printf.
Aaron Davies

@AaronDavies-아, 맞아. 파일 이름이 포함되어 있다고 가정했습니다. 물론 다음과 같이 이식 가능하다.find .//. \!. -name . -prune | grep -c '^\.//\.'
mikeserv

훌륭한! /파일 이름에 표시 할 수없는 유일한 다른 문자이므로 .//.시퀀스는 모든 파일에 대해 정확히 한 번만 나타납니다. 몇 가지 질문-왜 .//., 왜 -prune? 이것은 언제와 다릅니 find . \! -name . | grep -c '^\.'까? (내가 .당신 \!.의 오타 라고 가정합니다 .)
Aaron Davies
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.