2010-03-23 2 views
5

Cygwin에서 실행하는 쉘 스크립트에서 wc 유틸리티를 사용하고 있는데 출력에 "total"이있는 줄이 두 개 이상 있음을 발견했습니다.왜 wc 유틸리티가 "total"이있는 여러 줄을 생성합니까?

다음 기능은 내 소스 파일에서 라인의 수를 계산하는 데 사용됩니다

count_curdir_src() { 
    find . '(' -name '*.vb' -o -name '*.cs' ')' \ 
     -a '!' -iname '*.Designer.*' -a '!' -iname '.svn' -print0 | \ 
    xargs -0 wc -l 
} 

그러나 특정 디렉토리의 출력은 다음과 같습니다

그것은 화장실 재설정과 같은
$ find . '(' -name '*.vb' -o -name '*.cs' ')' -a '!' -iname '*.Designer.*' -a '!' -iname '.svn' -print0 | xargs -0 wc -l 
    19 ./dirA/fileABC.cs 
    640 ./dirA/subdir1/fileDEF.cs 
    507 ./dirA/subdir1/fileGHI.cs 
    2596 ./dirA/subdir1/fileJKL.cs 
(...many others...) 
    58 ./dirB/fileMNO.cs 
    36 ./dirB/subdir1/filePQR.cs 
122200 total 
    6022 ./dirB/subdir2/subsubdir/fileSTU.cs 
    24 ./dirC/fileVWX.cs 
(...) 
    36 ./dirZ/Properties/AssemblyInfo.cs 
    88 ./dirZ/fileYZ.cs 
25236 total 

그 과정의 어딘가에. -print0 옵션을 사용하기 때문에 파일 이름이나 디렉토리 이름에 공백 문자가 없어야합니다. 그리고 가장 큰 소스 트리에서 실행할 때만 발생합니다.

그래서 이것은 wc 나 Cygwin의 버그입니까? 또는 다른 것? 화장실 맨은 말한다 :

인쇄 개행 문자, 단어, 바이트는 각 파일에 대해 을 계산하고 하나 이하의 파일은 전체 라인을 지정합니다.

여기에는 여러 개의 총계 (중간 총계 또는 무언가)에 대한 언급이 없으므로 누가 여기에 책임이 있습니까?

답변

2

xargs에서 제공하는 입력 인수의 "배치"마다 한 번씩 wc를 호출합니다. 일괄 처리 당 하나의 총계가 생성됩니다.

하나의 대안은 wc의 임시 파일과 --files0-from 옵션을 사용하는 것입니다 xargswc 여러 번 실행되고 있는지 무슨 일

$ find . '(' -name '*.vb' -o -name '*.cs' ')' -a '!' -iname '*.Designer.*' -a 
    '!' -iname '.svn' -print0 > files 

$ wc --files0-from files 
+1

두 가지 : xargs가 일괄 처리되는 이유는 시스템의 제한 사항을 보여주는'xargs --show-limits'에서 볼 수 있습니다. 그리고 파이핑과'--files0-from = -'을 사용하여 파일을 생성하는 것을 피할 수 있습니다. – Xavier

+0

@Xavier : 그 정보로 자신의 답을 추가 할 가치가 있습니다. –

4

입니다. xargs은 기본적으로 실행될 명령의 각 호출에 대해 생각할 수있는 많은 인수를 일괄 처리하지만 너무 많은 파일이있는 경우 파일의 하위 집합에서 여러 번 명령을 실행합니다.

이 문제를 해결하기 위해 몇 가지 방법이 있습니다. 첫 번째 파일은 파일 수가 너무 많으면 깨질 것이며 xargs을 건너 뛰고 셸을 사용하는 것입니다. Cygwin에서는 제대로 작동하지 않지만 다음과 같이 보일 수 있습니다.

wc -l $(find . '(' -name '*.vb' -o -name '*.cs' ')' \ 
    -a '!' -iname '*.Designer.*' -a '!' -iname '.svn') 

그리고 print0 기능도 손실됩니다.

다른 하나는, 당신의 find/xargs 콤보의 출력을 처리하는 awk (또는 perl) 스크립트를 사용하여 "전체"라인을 건너 뛰고 총 자신을 요약하는 것입니다.

2

cygwin에서 명령 줄 길이가 표준 Linux 상자보다 훨씬 제한적이며 xargs은 이러한 제한을 고려하여 입력을 분할해야합니다.Cygwin에서에

: CentOS는에

$ xargs --show-limits < /dev/null 
Your environment variables take up 4913 bytes 
POSIX upper limit on argument length (this system): 25039 
POSIX smallest allowable upper limit on argument length (all systems): 4096 
Maximum length of command we could actually use: 20126 
Size of command buffer we are actually using: 25039 

: 당신은 xargs --show-limits와 한계를 확인할 수 있습니다

$ xargs --show-limits < /dev/null 
Your environment variables take up 1816 bytes 
POSIX upper limit on argument length (this system): 2617576 
POSIX smallest allowable upper limit on argument length (all systems): 4096 
Maximum length of command we could actually use: 2615760 
Size of command buffer we are actually using: 131072 

그리고 @ JonSkeet의 대답에 구축을, 당신은 추가 파일을 만들 필요가 없습니다 , 결과를 에 -을 전달하여 검색 결과를 직접 wipe 할 수 있습니다.

find . -name '*.vb' -print0 | wc -l --files0-from=- 
명령 행 인수로 파일 경로의 거대한 숫자로 wc 유틸리티를 공급하는 경우 3,691,363,210
0

당신이 wc의 표준 입력에 파일의 중간 xargscat에 대한 내용을 사용할 수 있습니다, "총"카운트에 여러 줄의 발생을 방지하기 위해 (참조 piping output of find to xargs wc gives unreasonable totals).

wc 명령에 Xavier에서 언급 한 --files0-from이없는 경우이 문제를 해결할 수 있습니다.

count_curdir_src() (
    export LC_ALL=C 
    find . -name '*.vb' -print0 | xargs -0 -n 1000 cat | wc -l 
) 
관련 문제