모든 .txt 파일의 총 줄 수를 계산하는 방법은 무엇입니까?

모든 .txt 파일의 총 줄 수를 계산하는 방법은 무엇입니까?

모든 .txt 파일에서 총 줄 수를 얻는 방법을 알아내려고 합니다. 문제는 6 -> 줄에 있다고 생각합니다 let $((total = total + count )). 이 형식을 수정하는 방법이 무엇인지 아는 사람이 있나요?

#!/bin/bash
total=0
find /home -type f -name "*.txt" | while read -r FILE; do
          count=$(grep -c ^ < "$FILE")
           echo "$FILE has $count lines"
           let $((total = total + count ))
        done
        echo TOTAL LINES COUNTED:  $total

감사합니다

답변1

6번째 줄은 다음과 같이 작성하는 것이 더 좋습니다.

total=$(( total + count ))

...하지만 다음과 같은 도구를 사용하는 것이 더 나을 것입니다.만들어진줄 수 계산(개행 수, 즉 적절하게 종료된 줄 수를 계산한다고 가정)

find . -name '*.txt' -type f -exec cat {} + | wc -l

이는 파일 이름이 .txt. 이러한 모든 파일은 단일 스트림으로 연결되어 로 파이프되며 wc -l, 이는 질문의 제목과 텍스트에서 요구하는 총 줄 수를 출력합니다.

전체 스크립트:

#!/bin/sh

nlines=$( find . -name '*.txt' -type f -exec cat {} + | wc -l )

printf 'Total number of lines: %d\n' "$nlines"

개별 파일의 줄 수도 얻으려면 다음을 고려하십시오.

find . -name '*.txt' -type f -exec sh -c '
    wc -l "$@" |
    if [ "$#" -gt 1 ]; then
        sed "\$d"
    else
        cat
    fi' sh {} + |
awk '{ tot += $1 } END { printf "Total: %d\n", tot }; 1'

이는 wc -l파일 배치를 호출하여 각 개별 파일에 대한 줄 수를 출력합니다. 둘 이상의 파일 이름으로 호출 되면 wc -l끝에 총 개수가 포함된 줄이 출력됩니다. sed인라인 sh -c스크립트가 둘 이상의 파일 이름 인수로 호출 되면 이 줄을 삭제합니다 .

그런 다음 줄 수와 파일 경로 이름의 긴 목록이 에 전달되는데 awk, 이는 단순히 수를 더하고 데이터를 전달하고 마지막에 총 수를 사용자에게 표시합니다.


GNU 시스템에서 이 wc도구는 Null로 구분된 스트림에서 경로 이름을 읽을 수 있습니다. 다음과 같이 이러한 시스템에서 해당 작업을 find사용할 수 있습니다 .-print0

find . -name '*.txt' -type f -print0 |
wc --files0-from=- -l

여기서 발견된 경로 이름은 wc비표준 -print0. 이 wc유틸리티는 비표준 --files0-from옵션과 함께 사용되어 파이프를 통해 전달되는 목록을 읽습니다.

답변2

let $((total = total + count ))

let이것은 작동하지만 둘 다 $(( .. ))산술 확장을 시작하므로 약간 중복됩니다 .

let "total = total + count", let "total += count"또는 중 하나 : $((total = total + count))라도 total=$((total + count))중복 없이 수행할 수 있습니다. 마지막 두 개는 표준 쉘과 호환되어야 하지만 let그렇지 않습니다.

total=0
find /home -type f -name "*.txt" | while read -r FILE; do
    total=...
done
echo TOTAL LINES COUNTED:  $total

무슨 문제를 의미하는지 말하지 않았지만 여기서 문제 중 하나는 Bash에서 파이프라인의 일부가 기본적으로 하위 셸에서 실행되므로 루프 total내부 에 대한 변경 사항이 while루프 이후에는 표시되지 않는다는 것입니다. 보다:내 변수가 하나의 '읽는 동안' 루프에서는 로컬이지만 겉보기에 유사한 다른 루프에서는 로컬이 아닌 이유는 무엇입니까?

shopt -s lastpipe파이프라인의 마지막 부분을 셸에서 실행하는 데 사용할 수 있습니다 . 또는 while및 그룹화 echo:

find ... | { while ...
    done; echo "$total"; }

물론 find ... | while read -r FILE;개행 문자가 포함되거나 공백으로 시작/끝나는 파일 이름에는 문제가 있습니다. 당신은 그것을 고칠 수 있습니다

find ... -print0 | while IFS= read -r -d '' FILE; do ...

또는 파일별 줄 수 분석에 신경 쓰지 않고 파일이 완전한 텍스트 파일이고 최종 줄 바꿈이 누락되지 않은 경우 모든 파일을 함께 연결하고 실행할 수 있습니다 wc -l.

파일의 마지막 줄 끝에 개행 문자가 누락되어 있고 불완전한 마지막 줄의 개수를 계산하려는 경우에는 그렇게 할 수 grep -c ^없으며 wc -l. (마지막 부분 줄을 세는 것이 grep -c ^. 대신 사용하는 유일한 이유입니다 wc -l.)

보다:파일 끝에 새 줄을 추가하는 것이 무슨 의미가 있나요?그리고텍스트 파일이 줄바꿈으로 끝나야 하는 이유는 무엇입니까?그래서.

또한 총 개수만 원하고 패턴과 일치하는 모든 파일이 일반 파일이고(따라서 테스트 -type f를 삭제할 수 있음) Bash 및 GNU grep이 있는 경우 다음을 수행할 수도 있습니다.

shopt -s globstar
shopt -s dotglob
grep -h -c ^ **/*.txt | awk '{ a += $0 } END { print a }'

**/*.txt재귀적 글로브이므로 작동하려면 명시적으로 활성화해야 합니다. dotglob해당 glob이 점으로 시작하는 파일 이름과도 일치하도록 만듭니다. grep -h출력에서 파일 이름을 억제하고 awk스크립트는 합계를 계산합니다. 파일 이름이 인쇄되지 않으므로 일부 문제가 있더라도 작동합니다.

또는 @fra-san이 제안한 대로 현재 삭제된 다른 답변을 기반으로 합니다.

grep -r -c -h --include='*.sh' ^ |awk '{ a+= $0 } END {print a }'

답변3

let total+=count$(( ))작동할 것입니다. 이러한 형태의 산술 평가 는 필요하지 않습니다 .

하지만 로 이 작업을 수행하는 것이 훨씬 나을 것입니다 wc -l.

find /home -type f -name '*.txt' -exec wc -l {} +

위의 쉘 스크립트에서와 같이 사용자 정의 출력을 원하거나 Linux에서 bash의 ~2MB 행 길이 제한에 맞는 것보다 더 많은 파일 이름이 있을 가능성이 있는 경우 또는 를 사용하여 awk계산 perl을 수행할 수 있습니다. 쉘을 읽는 동안 루프를 사용하는 것보다 더 나은 것은 무엇이든 있습니다(참조쉘 루프를 사용하여 텍스트를 처리하는 것이 나쁜 습관으로 간주되는 이유는 무엇입니까?). 예를 들어:

find /home -type f -name '*.txt' -exec perl -lne '
  $files{$ARGV}++;

  END {
    foreach (sort keys %files) {
      printf "%s has %s lines\n", $_, $files{$_};
      $total+=$files{$_}
    };
    printf "TOTAL LINES COUNTED: %s\n", $total
  }' {} +

참고: find ... -exec perl위의 명령은 빈 파일을 무시하지만 wc -l버전에서는 줄 수가 0인 파일을 나열합니다. Perl에서도 동일한 작업을 수행하도록 할 수 있습니다(아래 참조).

OTOH, 줄 수와 합계를 계산합니다.어느하나의 쉘 명령줄에 모두 맞지 않더라도 파일 수 - wc -l버전이 인쇄됩니다.이 경우에는 더 많은 total줄이 발생합니다. 아마도 발생하지 않을 수도 있지만 발생했다면 원하는 결과가 아닐 수도 있습니다.

이것은 작동해야 하며 wc -l출력을 Perl로 사용하고 파이프하여 원하는 출력 형식으로 변경합니다.

$ find /home -type f -name '*.txt' -exec wc -l {} + |
    perl -lne 'next if m/^\s+\d+\s+total$/;
               s/\s+(\d+)\s+(.*)/$2 has $1 lines/;
               print;
               $total += $1;

               END { print "TOTAL LINES COUNTED:  $total"}'

답변4

이 시도:

#!/bin/bash
export total=$(find . -name '*.txt' -exec wc -l "{}" ";" | awk 'BEGIN{sum=0} {sum+=$1} END{print sum}')
echo TOTAL LINES COUNTED ${total}

관련 정보