Contar todas as ocorrências de uma string em muitos arquivos com grep


289

Eu tenho um monte de arquivos de log. Preciso descobrir quantas vezes uma string ocorre em todos os arquivos.

grep -c string *

retorna

...
file1:1
file2:0
file3:0
...

Usando um pipe, consegui obter apenas arquivos com uma ou mais ocorrências:

grep -c string * | grep -v :0

...
file4:5
file5:1
file6:2
...

Como posso obter apenas a contagem combinada? (Se retornar file4:5, file5:1, file6:2, eu quero voltar 8.)


1
Você pode me dizer o que o grep -v: 0 faz? . Eu sei que conta para arquivos com ocorrências maiores que 0. O que significa a opção -v e: 0? Por favor me avise.
Gautham Honnavara

@GauthamHonnavara grep: 0 procura a linha que corresponde à sequência: 0. -v é uma opção para inverter essa pesquisa, portanto, usando grep -v: 0 significa encontrar todas as linhas que não contêm: 0 para que uma linha com file4: 5 e file27: 193 passasse, pois não contém: 0
penguin359

Você pode selecionar vários arquivos usando espaço. grep file1 file2 --options
Dnyaneshwar Harer 27/09/19

Respostas:


288
cat * | grep -c string

9
Isso tem a mesma limitação que conta várias ocorrências em uma linha apenas uma vez. No entanto, acho que esse comportamento é bom neste caso.
Michael Haren

@ Michael Haren Sim, poderia haver apenas uma ocorrência de string em uma linha.
Željko Filipin

2
Eu prefiro fazê-lo grep -c string<*Apenas substituindo o espaço por um menor que.
JamesM-SiteGen

48
Não aborda várias ocorrências em uma linha
bluesman

2
Isso não funciona se você deseja pesquisar em subdiretórios também, enquanto grep -oe wc -lfaz. gato é mais rápido em casos como a pergunta original.
Leagsaidh Gordon

296

Isso funciona para várias ocorrências por linha:

grep -o string * | wc -l

2
Isso também funciona: grep -o string * --exclude-dir=some/dir/one/ --exclude-dir=some/dir/two | wc -l.
codificador

2
grep -ioR string * | wc -lé o que eu uso para fazer um case-insensitive, recursivo, correspondência somente procurar
LeonardChallis

2
Este mostra os arquivos relevantes e, em seguida, a contagem total de correspondências:grep -rc test . | awk -F: '$NF > 0 {x+=$NF; $NF=""; print} END{print "Total:",x}'
Yaron 6/17

28
grep -oh string * | wc -w

contará várias ocorrências em uma linha


24
grep -oh "... my that curry was strong" * >> wc:)
icc97 23/03

23

Em vez de usar -c, basta canalizá-lo para wc -l.

grep string * | wc -l

Isso listará cada ocorrência em uma única linha e depois contará o número de linhas.

Porém, isso ocorrerá nos casos em que a sequência ocorrer mais de 2 vezes em uma linha.


2
A canalização para "wc -l" também funciona bem em conjunto com "grep -r 'test'". que verifica recursivamente todos os arquivos em busca da string 'test' em todos os diretórios abaixo do atual.
Stevek


9

Algo diferente de todas as respostas anteriores:

perl -lne '$count++ for m/<pattern>/g;END{print $count}' *

É bom ver uma abordagem que não usa grep, esp, pois meu grep (no Windows) não suporta a opção -o.
David Roussel

9

Você pode adicionar -Rà pesquisa recursivamente (e evitar o uso de cat) e -Iignorar arquivos binários.

grep -RIc string .

7

Solução AWK obrigatória:

grep -c string * | awk 'BEGIN{FS=":"}{x+=$2}END{print x}'

Tome cuidado se os nomes dos arquivos incluírem ":".


5

A solução AWK, que também lida com nomes de arquivos, incluindo dois pontos:

grep -c string * | sed -r 's/^.*://' | awk 'BEGIN{}{x+=$1}END{print x}'

Lembre-se de que esse método ainda não encontra várias ocorrências stringna mesma linha.


4

Se você deseja um número de ocorrências por arquivo (exemplo para a sequência "tcp"):

grep -RIci "tcp" . | awk -v FS=":" -v OFS="\t" '$2>0 { print $2, $1 }' | sort -hr

Exemplo de saída:

53  ./HTTPClient/src/HTTPClient.cpp
21  ./WiFi/src/WiFiSTA.cpp
19  ./WiFi/src/ETH.cpp
13  ./WiFi/src/WiFiAP.cpp
4   ./WiFi/src/WiFiClient.cpp
4   ./HTTPClient/src/HTTPClient.h
3   ./WiFi/src/WiFiGeneric.cpp
2   ./WiFi/examples/WiFiClientBasic/WiFiClientBasic.ino
2   ./WiFiClientSecure/src/ssl_client.cpp
1   ./WiFi/src/WiFiServer.cpp

Explicação:

  • grep -RIci NEEDLE . - procura a string NEEDLE recursivamente no diretório atual (seguindo links simbólicos), ignorando binários, contando o número de ocorrências, ignorando maiúsculas e minúsculas
  • awk ... - este comando ignora arquivos com zero ocorrências e formata linhas
  • sort -hr - classifica as linhas na ordem inversa por números na primeira coluna

Obviamente, ele funciona com outros comandos grep com a opção -c(count) também. Por exemplo:

grep -c "tcp" *.txt | awk -v FS=":" -v OFS="\t" '$2>0 { print $2, $1 }' | sort -hr

3

Você pode usar um simples greppara capturar efetivamente o número de ocorrências. Usarei a -iopção para garantir que STRING/StrING/stringseja capturado corretamente.

Linha de comando que fornece o nome dos arquivos:

grep -oci string * | grep -v :0

Linha de comando que remove os nomes dos arquivos e imprime 0 se houver um arquivo sem ocorrências:

grep -ochi string *

Você poderia elaborar mais sua resposta adicionando um pouco mais de descrição sobre a solução que você fornece?
abarisone

3

variante recursiva curta :

find . -type f -exec cat {} + | grep -c 'string'

1
Obrigado! Somente sua solução funcionou para mim (resumiu as correspondências de todos os arquivos).
Nestor

1

Solução somente para grep que testei com grep para windows:

grep -ro "pattern to find in files" "Directory to recursively search" | grep -c "pattern to find in files"

Esta solução contará todas as ocorrências, mesmo se houver várias em uma linha. -rpesquisa recursivamente no diretório, -o"mostra apenas a parte de uma linha que corresponde ao PADRÃO" - é isso que divide várias ocorrências em uma única linha e faz grep imprimir cada correspondência em uma nova linha; canalize esses resultados separados por nova linha de volta ao grep -cpara contar o número de ocorrências usando o mesmo padrão.


1

Aqui está uma maneira alternativa do AWK mais rápida que a grep, que lida com várias correspondências <url>por linha, em uma coleção de arquivos XML em um diretório:

awk '/<url>/{m=gsub("<url>","");total+=m}END{print total}' some_directory/*.xml

Isso funciona bem nos casos em que alguns arquivos XML não possuem quebras de linha.


0

Outro oneliner usando funções básicas de linha de comando, manipulando várias ocorrências por linha.

 cat * |sed s/string/\\\nstring\ /g |grep string |wc -l
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.