Como contar ocorrências de todas as palavras em todos os arquivos de um diretório usando o grep? Mas com contagem incrementada apenas uma vez por palavra por arquivo

5

Já fiz uma pergunta semelhante, mas as pessoas entenderam mal o que eu estava perguntando. Eu estava perguntando como gerar uma lista de cada palavra com uma contagem de palavras incrementada apenas uma vez por palavra por arquivo.

Por exemplo, eu tenho um diretório com 10 arquivos, eu quero gerar uma lista de palavras usando comandos bash que dizem um valor de 1-10 dependendo de quantos arquivos eles aparecem:

10 The
10 and
8 bash
7 command
6 help....

etc.

Eu já sei que grep -l word *| wc -l pesquisará uma única palavra, mas quero criar uma lista de todas as palavras.

Existe uma maneira de combinar isso com tr '[A-Z]' '[a-z]' | tr -d '[:punct:]' para que palavras com letras maiúsculas não sejam duplicadas e a pontuação removida?

    
por Cnvrsn 14.12.2014 / 13:07

4 respostas

2

Eu usaria o perl aqui:

perl -T -lne '
  for (/\w+/g) {$count{lc $_}->{$ARGV}=undef}
  END {print "$_: " . keys %{$count{$_}} for keys %count}' ./*

Que cria um hash de hash $count{word} é uma referência a um hash cujas chaves são os nomes dos arquivos em que word é encontrado (e valores que não nos interessam, aqui configurados como undef ).

No final, apenas contamos o número de elementos (assim, o número de arquivos) para cada um desses hashes (portanto, para cada uma das palavras encontradas).

    
por 20.06.2016 / 08:30
1

Acabei de encontrar a resposta original do @Mehmet enquanto procurava por algo não relacionado e vejo que, embora funciona, é terrivelmente ineficiente, exigindo que cada arquivo seja lido novamente para cada palavra única em todos os arquivos! A segunda resposta de @Jeff é bastante complicada apesar da explicação e, pior de tudo, sofre com o cat file | sin!

Uma única passagem em todos os dados é tudo o que é necessário e pode ser formulada através da combinação eficaz das respostas anteriores:

find . -maxdepth 1 -type f -print |
while read file; do
    egrep -h -o "[[:alnum:]][[:alnum:]_-]*" "$file" |
    tr '[A-Z]' '[a-z]' |
    sed "s|^|$file\||"
done |
sort -t '|' -k 2 |
uniq |
awk -F '|' '{
    if (lw != $2) {
        print fc " " lw;
        fc = 0;
    }
    lw = $2;
    fc++;
}'

Observe que a escolha do separador de campos é importante se os nomes dos arquivos incluírem caminhos e / ou se eles incluem espaços. Eu escolhi o caractere | , pois ele nunca deve fazer parte de uma palavra impressa por egrep e é improvável que ele apareça em um arquivo ou nome de diretório.

    
por 20.05.2016 / 22:02
-1

Isso deve pegar todas as palavras de todos os arquivos, classificá-las e obter palavras únicas, do que iterar essas palavras e contar em quantos arquivos elas ocorrem.

# find all words from all files within the directory
grep -o -h -E '\w+' directory/*|sort -u | \
while read word;
do
        # iterate through each word and find how many files it occurs
        c='grep -l "$word" directory/*|wc -l'
        echo "$c $word";
done
    
por 14.12.2014 / 14:27
-1

Isto é como processar cada arquivo em um diretório individualmente:

for f in yourdirectory/*; do cat "$f" |

É assim que eu filtra tudo, menos palavras de dados de texto:

sed 's/\.$//;s/\.\([^0-9]\)//g;s/[][(),;:?!]//g' | tr [A-Z] [a-z] |

Mas o seu método também funciona bem. (Eu queria ter certeza de não remover hífens de palavras com hífen, nem apóstrofos de contrações.)

De qualquer forma, continue da seguinte forma:

tr -s ' ' '2' | sort -u ; done |

Isso cria uma lista de palavras por arquivo, agora apenas:

sort | uniq -c

Se você quiser a lista de menos frequente, apenas use |sort -nr .

Você também pode precisar adicionar uma pontuação adicional, como {} , à lista no final do sed acima, dependendo dos dados de entrada.

    
por 21.12.2015 / 00:05