
모든 .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}