grep conta várias ocorrências

6

É possível fazer uma contagem grep de várias ocorrências em um arquivo em um único comando? Por exemplo:

$ cat > file
blah alfa
beta blah
blah blahgamma
gamma

Eu posso fazer:

grep -c 'alfa' file 
1 
grep -c 'beta' file  
1
grep -c 'gamma' file  
2

Mas é possível domething assim:

grep -c -e 'alfa' -e 'beta' -e 'gamma' -somemoreblackmagic file

e obter as contagens para cada um deles?

alfa 1
beta 1
gamma 2
    
por 719016 08.01.2013 / 12:16

7 respostas

3

Eu não acho que o grep seja capaz do que você quer fazer.

Apenas use o awk em vez disso :-)

Esta solução pode não funcionar bem para arquivos grandes (não está otimizada). E funciona apenas para palavras simples - não regexps. Mas é fácil adicionar alguns recursos, se assim desejar.

Versão low end com restrições descritas nos comentários abaixo:

awk '
{
    split($0, b); for (i in b) ++A[b[i]]
}
END {
    split("'"$*"'", a)
    for (i in a) print sprintf("%s %d", a[i], A[a[i]])
}
'

apenas forneça as strings de pesquisa diretamente ao script

[EDITAR]
versão fixa com suporte a regex (veja o comentário abaixo). Por favor, diga-me se ainda há problemas em aberto.

# ---- my favorite ----
awk -F' ?-c ' '
BEGIN { split("'"$*"'", a) }
{ for (i = 2; a[i]; ++i) if (match($0, a[i])) ++A[i] }
END { for (i = 2; a[i]; ++i) if (A[i]) print a[i] " " A[i] }
'
# ---- my favorite ----

uso de amostra:

script_name -c alfa -c beta -c gamma << !
alfa
beta
gamma
gamma
!

dá:

alfa 1
beta 1
gamma 2

uso de regex:

script_name -c   "^al"    -c "beta" -c gamma -c "m.$" << !
alfa
beta
gamma
gamma
!

dá:

^al 1
beta 1
gamma 2
m.$ 2

[/ EDIT]

    
por 08.01.2013 / 12:46
3

Você pode obter o que precisa usando grep , classificar e uniq .

grep -EIho 'alfa|beta|gamma' *|sort|uniq -c
    
por 31.05.2015 / 11:54
3

Outra solução awk , com o wrapper do shell script lançado:

#!/bin/sh –
awk '
BEGIN { split("alfa beta gamma", keyword)
        for (i in keyword) count[keyword[i]]=0
}
/alfa/  { count["alfa"]++ }
/beta/  { count["beta"]++ }
/gamma/ { count["gamma"]++ }
END   {
        for (i in keyword) print keyword[i], count[keyword[i]]
}'

Se você quiser escolher as palavras-chave de pesquisa em tempo de execução (e fornecê-las como argumentos, como na resposta de Sparkie), esse script pode ser adaptado para criar dinamicamente o script awk .

    
por 08.01.2013 / 19:26
0

Solução de Perl:

perl -lne 'chomp;$s{$_}++ if /alpha|beta|gamma/ }{ print "$_ $s{$_}" for keys %s' file
    
por 08.01.2013 / 14:33
0

Nenhum grep pode fazer isso em uma única passagem, eu sugiro usar o awk:

awk -v pat='alfa beta gamma' '
  BEGIN { split(pat, p) } 

  { for(k in p) if($0 ~ p[k]) c[k]++ }

  END { for(k in p) print p[k], c[k]?c[k]:0 }
'

Ou como uma linha de expressão bastante longa:

awk -v pat='alfa beta gamma' 'BEGIN { split(pat, p) } { for(k in p) if($0 ~ p[k]) c[k]++ } END { for(k in p) print p[k], c[k]?c[k]:0 }'

Explicação

pat é dividido na matriz p , que é usada para procurar correspondências em cada linha ( $0 ~ p[k] ). Os contadores são mantidos na matriz c . O bit c[k]?c[k]:0 usa o operador ternário para imprimir 0 quando c[k] é zero.

Observe que, se o padrão contiver espaço, você precisará usar um delimitador diferente entre os padrões em pat e atualizar o comando split de acordo.

Teste

Entrada:

cat << EOF > file
alfa
beta
gamma
gamma
EOF

Saída com pat='alfa beta gamma' :

alfa 1
beta 1
gamma 2

Entrada:

cat << EOF > file
alfa beta
beta
gamma gamma
gamma alfa
alfalfa
alfa alfa
EOF

Saída com pat='^a a$ alfa beta gamma' :

beta 2                                          
gamma 2
^a 3
a$ 6
alfa 4

A saída corresponde em ambos os casos à saída de executar grep -c com cada padrão individualmente.

    
por 08.01.2013 / 14:46
0

Sugiro usar uniq (com sort ).

$ sort file | uniq -c
1 alfa
1 beta
2 gamma

Você precisa de sort se o arquivo não puder ser classificado (na verdade, apenas se as várias ocorrências não estiverem em linhas consecutivas).

ATUALIZAÇÃO:

Supondo que você tenha padrões predefinidos e não contenham espaço:

$ PATTERNS='alfa beta gamma'

$ for P in $PATTERNS; do echo $P 'grep -c $P file'; done
alfa 1
beta 1
gamma 2
    
por 09.01.2013 / 14:06
0

Aqui uma amostra do meu trabalho diário:

Todos os arquivos que terminam com FlowBase.java, Contagem de ocorrências de String "Input *" > 1

Exemplo: o arquivo será listado

"inputABD"

"inputABD"

$ para i em $ (find. | grep FlowBase.java); do echo $ i $ (egrep "entrada. " $ i | sed 's /^. "input //' | sed 's /";.*//' | uniq -c | awk '($ 1 > 1) {print $ 2}' | wc -l); feito | awk '($ 2 > 0) {print $ 1}'

    
por 16.04.2015 / 14:27

Tags