Suponha que você tenha um arquivo que contenha endereços IP, um endereço em cada linha:
10.0.10.1
10.0.10.1
10.0.10.3
10.0.10.2
10.0.10.1
Você precisa de um script de shell que conte para cada endereço IP quantas vezes ele aparece no arquivo. Para a entrada anterior, você precisa da seguinte saída:
10.0.10.1 3
10.0.10.2 1
10.0.10.3 1
Uma maneira de fazer isso é:
cat ip_addresses |uniq |while read ip
do
echo -n $ip" "
grep -c $ip ip_addresses
done
No entanto, está realmente longe de ser eficiente.
Como você resolveria esse problema com mais eficiência usando o bash?
(Uma coisa a acrescentar: eu sei que pode ser resolvido a partir de perl ou awk, estou interessado em uma solução melhor no bash, não nesses idiomas.)
INFORMAÇÃO ADICIONAL:
Suponha que o arquivo de origem tenha 5 GB e a máquina executando o algoritmo tenha 4 GB. Portanto, classificar não é uma solução eficiente, nem ler o arquivo mais de uma vez.
Gostei da solução semelhante à hashtable - alguém pode oferecer melhorias nessa solução?
INFORMAÇÕES ADICIONAIS # 2:
Algumas pessoas perguntaram por que eu me incomodaria em fazê-lo no bash, quando é muito mais fácil, por exemplo, em perl. O motivo é que na máquina que eu tinha que fazer esse perl não estava disponível para mim. Era uma máquina Linux customizada, sem a maioria das ferramentas que estou acostumada. E acho que foi um problema interessante.
Então, por favor, não culpe a pergunta, apenas a ignore se não gostar. :-)
Respostas:
Isso imprimirá a contagem primeiro, mas fora isso, deve ser exatamente o que você deseja.
fonte
sort ip_addresses | uniq -c | sort -nr
sort ip_addresses | uniq -c | sort -nr | awk '{ print $2, $1 }'
para obter o endereço IP na primeira coluna e contar na segunda.sort -nr -k1,1
O método rápido e sujo é o seguinte:
cat ip_addresses | sort -n | uniq -c
Se você precisar usar os valores no bash, poderá atribuir o comando inteiro a uma variável do bash e percorrer os resultados.
PS
Se o comando de classificação for omitido, você não obterá os resultados corretos, pois o uniq apenas analisa sucessivas linhas idênticas.
fonte
para resumir vários campos, com base em um grupo de campos existentes, use o exemplo abaixo: (substitua $ 1, $ 2, $ 3, $ 4 de acordo com seus requisitos)
fonte
sort
euniq
são mais fáceis para fazer a contagem, mas não ajuda quando você precisa para calcular / valores campos de soma. A sintaxe da matriz do awk é muito poderosa e essencial para agrupar aqui. Obrigado!print
função do awk parece reduzir o número inteiro de 64 bits para 32 bits; portanto, para valores int superiores a 2 ^ 31, convém usarprintf
com o parâmetro%.0f
formato em vez deprint
láarr[$1,$2]+=$3+$4
por, por exemplo,arr[$1,$2]=(arr[$1,$2] $3 "," $4). I needed this to provide a grouped-by-package list of files (two columns only) and used:
arr [$ 1] = (arr [$ 1] $ 2) `com sucesso.A solução canônica é a mencionada por outro entrevistado:
É mais curto e conciso do que o que pode ser escrito em Perl ou awk.
Você escreve que não deseja usar a classificação, porque o tamanho dos dados é maior que o tamanho da memória principal da máquina. Não subestime a qualidade de implementação do comando de classificação Unix. A classificação foi usada para lidar com grandes volumes de dados (pense nos dados de cobrança originais da AT&T) em máquinas com 128k (131.072 bytes) de memória (PDP-11). Quando a classificação encontra mais dados do que um limite predefinido (geralmente ajustado perto do tamanho da memória principal da máquina), ela classifica os dados lidos na memória principal e os grava em um arquivo temporário. Em seguida, repete a ação com os próximos blocos de dados. Por fim, ele executa uma classificação de mesclagem nesses arquivos intermediários. Isso permite que a classificação funcione em dados muitas vezes maiores que a memória principal da máquina.
fonte
este comando daria a saída desejada
fonte
Parece que você precisa usar uma grande quantidade de código para simular hashes no bash para obter um comportamento linear ou seguir as versões superlineares
quadráticas.Entre essas versões, a solução da saua é a melhor (e mais simples):
Encontrei http://unix.derkeiler.com/Newsgroups/comp.unix.shell/2005-11/0118.html . Mas é feio como o inferno ...
fonte
Solução (agrupe como mysql)
Resultado
fonte
Você provavelmente pode usar o próprio sistema de arquivos como uma tabela de hash. Pseudocódigo da seguinte forma:
No final, tudo o que você precisa fazer é percorrer todos os arquivos e imprimir os nomes e números dos mesmos. Como alternativa, em vez de manter uma contagem, você pode acrescentar um espaço ou uma nova linha de cada vez ao arquivo e, no final, apenas ver o tamanho do arquivo em bytes.
fonte
Eu sinto matriz associativa awk também é útil neste caso
Um grupo por correio aqui
fonte
A maioria das outras soluções conta duplicatas. Se você realmente precisar agrupar pares de valores-chave, tente o seguinte:
Aqui estão os meus dados de exemplo:
Isso imprimirá os pares de valores-chave agrupados pela soma de verificação md5.
fonte
Puro festança (sem garfo!)
Existe uma maneira, usando um festançafunção . Desta forma, é muito rápido, pois não há garfo! ...
... Enquanto vários endereços IP permanecem pequenos !
Nota: Os endereços IP são convertidos em um valor inteiro não assinado de 32 bits, usado como índice para a matriz . Este usa matrizes simples do bash , não o array associativo (que é mais caro)!
No meu host, fazer isso é muito mais rápido do que usar garfos, até aproximadamente 1'000 endereços, mas leva aproximadamente 1 segundo inteiro quando vou tentar classificar e contar 10'000 endereços.
fonte
Eu teria feito assim:
mas o uniq pode funcionar para você.
fonte
Entendo que você está procurando algo no Bash, mas, caso outra pessoa esteja procurando algo no Python, considere o seguinte:
Como os valores no conjunto são únicos por padrão e o Python é muito bom nisso, você pode ganhar algo aqui. Como não testei o código, ele pode estar com erros, mas isso pode levá-lo até lá. E se você deseja contar ocorrências, é fácil implementar um ditado em vez de um conjunto.
Edit: Eu sou um péssimo leitor, então eu respondi errado. Aqui está um trecho com um ditado que contaria ocorrências.
O dicionário mydict agora contém uma lista de IPs exclusivos como chaves e a quantidade de vezes que ocorreram como seus valores.
fonte
itertools.groupby()
que combinado comsorted()
faz exatamente o que o OP pede.A classificação pode ser omitida se o pedido não for significativo
ou
se a lista de fontes for uma variável
fonte