grep을 사용하여 총 발생 수 계산


215

grep -c파일에서 문자열이 몇 번이나 발생하는지 찾는 데 유용하지만 한 줄에 한 번만 발생합니다. 한 줄에 여러 번 발생하는 횟수를 계산하는 방법은 무엇입니까?

나는 다음보다 더 우아한 것을 찾고 있습니다.

perl -e '$_ = <>; print scalar ( () = m/needle/g ), "\n"'

4
나는 grep지정되었지만 알고 있는 사람에게는 ack답은 간단 ack -ch <pattern>합니다.
Kyle Strand

답변:


302

grep -o은 라인을 무시하고 경기 만 출력합니다. wc그들을 셀 수 있습니다 :

grep -o 'needle' file | wc -l

'니들'또는 '멀티 니들'과도 일치합니다.
한 마디 만 :

grep -o '\bneedle\B' file | wc -l
# or:
grep -o '\<needle\>' file | wc -l

6
여기에는 GNU grep (Linux, Cygwin, FreeBSD, OSX)이 필요합니다.
Gilles

@wag 어떤 마법을 않습니다 \b\B여기에서?
Geek

6
@Geek \ b는 단어 경계와 일치하고 \ B는 단어 경계와 일치하지 않습니다. 위의 대답은 양쪽 끝에 \ b를 사용하면 더 정확합니다.
Liam

1
줄당 발생 횟수를 보려면 grep -n 옵션 및 uniq -c ... grep -no '\ <needle \>'파일 | uniq -c
jameswarren

@jameswarren uniq은 인접한 동일한 줄만 제거하므로 중복 항목이 항상 즉시 인접하는지 확실하지 않은 경우 sort급지하기 전에 공급 해야합니다 uniq.
tripleee

16

당신이 (항상 가끔 다른 곳에서 리눅스와 Cygwin에서에) GNU의 GREP이있는 경우, 당신은 할 수 의 출력 라인을 계산grep -o : grep -o needle | wc -l.

Perl을 사용하면 다음보다 더 우아하게 찾을 수있는 몇 가지 방법이 있습니다 ( 고정 된 후에도 ).

perl -lne 'END {print $c} map ++$c, /needle/g'
perl -lne 'END {print $c} $c += s/needle//g'
perl -lne 'END {print $c} ++$c while /needle/g'

POSIX 도구 만 사용하는 경우 가능한 한 방법은 입력을 grep에 전달하기 전에 단일 일치로 입력을 분할하는 것입니다. 예를 들어 전체 단어를 찾으려면 먼저 단어가 아닌 모든 문자를 줄 바꿈으로 바꾸십시오.

# equivalent to grep -ow 'needle' | wc -l
tr -c '[:alnum:]' '[\n*]' | grep -c '^needle$'

그렇지 않으면이 특정 비트의 텍스트 처리를 수행하는 표준 명령이 없으므로 sed (마조히스트 인 경우) 또는 awk로 전환해야합니다.

awk '{while (match($0, /set/)) {++c; $0=substr($0, RSTART+RLENGTH)}}
     END {print c}'
sed -n -e 's/set/\n&\n/g' -e 's/^/\n/' -e 's/$/\n/' \
       -e 's/\n[^\n]*\n/\n/g' -e 's/^\n//' -e 's/\n$//' \
       -e '/./p' | wc -l

다음은 sedand를 사용하는 더 간단한 솔루션 grep입니다. 문자열이나 심지어는 정규 표현식에도 작동하지만 앵커 패턴이있는 몇 가지 모퉁이에서는 실패합니다 (예 : ^needle또는 \bneedle에서 두 번 발생 needleneedle).

sed 's/needle/\n&\n/g' | grep -cx 'needle'

위의 sed 대체 \n에서 줄 바꿈을 의미했습니다. 이것은 패턴 부분의 표준이지만 대체 텍스트에서는 이식성을 위해 backslash-newline을 대체합니다 \n.


4

나처럼 실제로 "둘 다; 정확히 한 번" (이것은 실제로 "둘 중 하나")을 원한다면 간단합니다.

grep -E "thing1|thing2" -c

출력을 확인하십시오 2.

이 방법의 장점은 (정확히 한 번만 경우 입니다 당신이 원하는) 쉽게 확장 할 것입니다.


실제로 한 번만 나타나는지 확실하지 않습니까? 당신이 찾고있는 것은 그 단어 중 하나가 적어도 한 번 존재한다는 것입니다.
Steve Gore

3

awk needle를 필드 분리 자로 사용하는 또 다른 솔루션 :

awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'

일치 needle하고 구두점 을 찾으려면 필드 구분 기호를 적절하게 변경하십시오.

awk -F'^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$' '{c+=NF-1}END{print c}'

또는 class : [^[:alnum:]]를 사용하여 모든 비 알파 문자를 포함하십시오.


정규 표현식 필드 구분 기호 (GNU awk 등)를 지원하는 awk가 필요합니다.
Gilles

1

귀하의 예제는 파일의 총계가 아닌 한 줄당 발생 횟수 만 인쇄합니다. 이것이 원하는 경우 다음과 같이 작동 할 수 있습니다.

perl -nle '$c+=scalar(()=m/needle/g);END{print $c}' 

당신이 옳습니다-나의 예제는 첫 번째 줄에서 발생하는 횟수 만 계산합니다.

1

이것은 내 순수한 bash 솔루션입니다

#!/bin/bash

B=$(for i in $(cat /tmp/a | sort -u); do
echo "$(grep $i /tmp/a | wc -l) $i"
done)

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