Podemos fazer isso inteiramente usando apenas awk
:
awk -F, 'BEGIN{print"\"Time Interval\",\"Count of Sources\""}NR>1{gsub(/"/,"",);h=int(/10000)*10000;m=int((-h)/3000)*3000;ctr[h+m]++}END{n=asorti(ctr,idx);for(i=1;i<=n;i++){print "\""idx[i]"\",\""ctr[idx[i]]"\""}}' fb.csv
Para o arquivo de entrada fornecido fb.csv
, isso resulta na saída
"120000","4"
"123000","7"
"130000","8"
"133000","5"
"140000","7"
Importante: Isso requer que o GNU AWK ( gawk
) seja executado, porque ele usa a função asorti(...)
para classificar matrizes associativas por seus índices. Não funciona com mawk
. Você pode descobrir sua versão awk
padrão usando awk -Wv
.
Explicação do comando:
Corremos awk
assim, definindo o separador de campos que delimita as colunas para ,
e usando o arquivo fb.csv
como entrada:
awk -F, '<COMMAND>' fb.csv
O comando awk
(espaço reservado <COMMAND>
acima) é este, após a formatação adequada:
BEGIN {
print "\"Time Interval\",\"Count of Sources\""
}
NR>1 {
gsub(/"/, "", )
h = int( / 10000) * 10000
m = int((-h) / 3000) * 3000
ctr[h+m]++
}
END {
n = asorti(ctr, idx)
for(i=1; i<=n; i++) {
print "\"" idx[i] "\",\"" ctr[idx[i]] "\""
}
}
Isso parece terrivelmente complicado (e não posso negar que é preciso pensar um pouco para entender), então vou tentar dividir um pouco:
O bloco de código BEGIN { ... }
será executado uma vez antes da primeira linha de entrada do arquivo ser lida. Então, para cada linha exceto a primeira ("número de linha maior que 1"), o bloco NR>1 { ... }
é executado. Finalmente, depois que toda a entrada for lida, o bloco END { ... }
será executado.
-
Agora, o bloco
BEGIN
é bastante direto, ele imprime apenas a nova linha de cabeçalho CSV. -
Vamos ver o bloco
NR>1
. Lembre-se queawk
divide cada linha em campos, que foram separados pelo delimitador de campo (aquele que definimos como,
usando o argumento-F
). A primeira coluna / campo será armazenada na variável, a segunda em
e assim por diante. Estamos interessados apenas no valor do segundo campo, que contém o tempo.
Usando a função
gsub(<PATTERN>, <REPLACEMENT>, <VARIABLE>)
, substituímos todas as ocorrências de<PATTERN>
(uma expressão regular incluída em barras, aqui ela simplesmente corresponde apenas às aspas) com um<REPLACEMENT>
(vazio, pois queremos removê-las) string em<VARIABLE>
(ou seja, o segundo campo contendo o tempo aqui).
Em seguida, decodificamos o registro de data e hora em horas inteiras
h
(multiplicado por 10000) e metade das horas inteirasm
(sem as horas completas; multiplicado por 3000). Usamos uma matriz associativactr
como contador de quantas vezes o carimbo de hora arredondadoh+m
ocorre na entrada. -
Finalmente, no bloco
END
, imprimimos os valores do contador classificados pelo registro de data e hora arredondado índices.