Forma elegante de contar quantas vezes os padrões de um arquivo ocorrem em outro arquivo

1

Imagine que temos dois arquivos, por exemplo. O primeiro arquivo é preenchido com nomes exclusivos de funcionários criados pela combinação dos dois primeiros caracteres do primeiro nome e dos dois últimos caracteres do sobrenome. Example : Peter Smith - Peht

O primeiro arquivo contém:

Peht
Mawo
Stso
Makr
Bavo

O segundo arquivo contém gravações sobre eles quando se conectaram ao sistema. (Obviamente, há também funcionários que não estão listados em file1 .)

O segundo arquivo:

Mawo 21.4.2016 17:49
Peht 21.4.2016 17:58
Mawo 22.4.2016 7:58
Wato 22.4.2016 7:59
Stso 22.4.2016 8:02
Bavo 22.4.2016 8:15
Bane 22.4.2016 9:01
Bavo 23.4.2016 9:12
Mawo 23.4.2016 9:24
Dalo 23.4.2016 9:54
Peht 23.4.2016 9:58
Grma 24.4.2016 10:00

I need to find out how many times employes from file1 connected to the system ( file2 ).

Qual é a melhor maneira de fazer isso? A única solução que me veio à mente é fazer uns 2 loops e para cada nome de file1 fazer o loop de todos os nomes file2 then grep , perguntar se os nomes coincidem se sim então count++ . Alguém poderia me dar alguma solução elegante para este problema usando por exemplo awk se é possível?

    
por pnom 27.04.2016 / 17:43

3 respostas

2

Algo simples como:

mapfile -t names < file1
for name in "${names[@]}"
do
  echo "${name}" $(grep -c "^$name " file2)
done

fornecerá resultados como:

Peht 2
Mawo 3
Stso 1
Makr 0
Bavo 2

A string grep diz para ancorar o nome de usuário no início (^) da linha e aplicar um espaço à direita depois da linha.

    
por 27.04.2016 / 17:57
2

test.awk:

FNR == NR{ 
  names[$1]
  next
}   
($1 in names){
  ulog[$1]++
}   
END{
  for(name in ulog){
    print name ":" ulog[name]
  }   
}   

e execute-o como awk -f test.awk user.list user.log

FNR == NR # faz o número do registro do arquivo == o número do registro, se isso acontecer, então ainda estamos no primeiro arquivo

next # como ainda estamos no primeiro arquivo, pule o resto e puxe a próxima linha

O resto deve ser autoexplicativo

ou como um one-liner

awk 'FNR == NR{ names[$1]; next } ($1 in names){ ulog[$1]++ } END{ for(name in ulog){ print name ":" ulog[name] } }' user.list user.log

    
por 27.04.2016 / 18:07
0

Aqui está outra forma com join / sort / uniq :

join  -1 1 -2 2 -a1 -e "0" -o 1.1 2.1 <(sort file1) \
<(cut -d' ' -f1 file2 | sort | uniq -c)

Basicamente, ele une os nomes em file1 com os nomes uniq ue e conta de file2 usando 0 para os campos ausentes em file2 .

Com awk eu seria executado:

awk 'NR==FNR{s[$1]++;next}
{if ($1 in s) {print $1, s[$1]}
else {print $1, 0}}' file2 file1

Isso lê file2 primeiro, conta quantas vezes cada nome ocorre, então lê file1 e para cada nome imprime a contagem de file2 (se um nome não estiver em file2 , ele imprime 0). / p>     

por 27.04.2016 / 18:18