Question

J'ai un qui ressemble à ceci:

I, [2009-03-04T15:03:25.502546 #17925]  INFO -- : [8541, 931, 0, 0]
I, [2009-03-04T15:03:26.094855 #17925]  INFO -- : [8545, 6678, 0, 0]
I, [2009-03-04T15:03:26.353079 #17925]  INFO -- : [5448, 1598, 185, 0]
I, [2009-03-04T15:03:26.360148 #17925]  INFO -- : [8555, 1747, 0, 0]
I, [2009-03-04T15:03:26.367523 #17925]  INFO -- : [7630, 278, 0, 0]
I, [2009-03-04T15:03:26.375845 #17925]  INFO -- : [7640, 286, 0, 0]
I, [2009-03-04T15:03:26.562425 #17925]  INFO -- : [5721, 896, 0, 0]
I, [2009-03-04T15:03:30.951336 #17925]  INFO -- : [8551, 4752, 1587, 1]
I, [2009-03-04T15:03:30.960007 #17925]  INFO -- : [5709, 5295, 0, 0]
I, [2009-03-04T15:03:30.966612 #17925]  INFO -- : [7252, 4928, 0, 0]
I, [2009-03-04T15:03:30.974251 #17925]  INFO -- : [8561, 4883, 1, 0]
I, [2009-03-04T15:03:31.230426 #17925]  INFO -- : [8563, 3866, 250, 0]
I, [2009-03-04T15:03:31.236830 #17925]  INFO -- : [8567, 4122, 0, 0]
I, [2009-03-04T15:03:32.056901 #17925]  INFO -- : [5696, 5902, 526, 1]
I, [2009-03-04T15:03:32.086004 #17925]  INFO -- : [5805, 793, 0, 0]
I, [2009-03-04T15:03:32.110039 #17925]  INFO -- : [5786, 818, 0, 0]
I, [2009-03-04T15:03:32.131433 #17925]  INFO -- : [5777, 840, 0, 0]

J'aimerais créer un script shell qui calcule la moyenne des deuxième et troisième champs entre parenthèses ( 840 et 0 dans le dernier exemple). Une question encore plus ardue: est-il possible d’obtenir la moyenne du 3ème champ uniquement lorsque le dernier n'est pas 0 ?

Je sais que je pourrais utiliser Ruby ou un autre langage pour créer un script, mais j'aimerais le faire avec Bash . Toute bonne suggestion sur les ressources ou astuces sur la manière de créer un tel script serait utile.

Était-ce utile?

La solution

Publier la réponse que je vous ai collée par-dessus la messagerie instantanée ici aussi, juste parce que cela me fait essayer StackOverflow out:)

# replace $2 with the column you want to avg; 
awk '{ print $2 }' | perl -ne 'END{ printf "%.2f\n", $total/$n }; chomp; $total+= 

Publier la réponse que je vous ai collée par-dessus la messagerie instantanée ici aussi, juste parce que cela me fait essayer StackOverflow out:)

<*>; $n++' < log

Autres conseils

Utilisez bash et awk :

  

fichier cat | sed -ne 's: ^. * INFO. * \ [\ ([0-9,] * \) \] [\ r] * $: \ 1: p' | awk -F '*, *' '{sum2 + = 2 $; sum3 + = $ 3} END {if (NR> 0) printf "avg2 =% 2f, avg3 =% 2f \ n", sum2 / NR, sum3 / NR} '

Exemple de sortie (pour vos données d'origine):

  

avg2 = 2859.59, avg3 = 149.94

Bien sûr, vous n'avez pas besoin d'utiliser cat , il est inclus ici pour des raisons de lisibilité et pour illustrer le fait que les données d'entrée peuvent provenir de n'importe quel canal. si vous devez utiliser un fichier existant, exécutez sed -ne '...' file | ... directement.

MODIFIER

Si vous avez accès à gawk (GNU awk), vous pouvez éliminer le besoin de sed comme suit:

  

fichier cat | gawk '{if (match ($ 0, /.*INFO.*\[([0-9,] *) \) [\ r] * $ /, a)) {cnt ++; scission (a [1], b, / *, * /); sum2 + = b [2]; sum3 + = b [3]}} FIN {if (cnt > 0) printf "quot2 =% 2f, avg3 =% 2f \ n ",sum2 / cnt, sum3 / cnt} '

Mêmes remarques concernant. cat s'applique.

Un peu d'explication:

  • sed n’imprime que les lignes (combinaison -n ...: p ) correspondant à l’expression régulière (lignes contenant INFO suivies de toute combinaison de chiffres, d'espaces et des virgules entre crochets à la fin de la ligne, permettant les espaces de fin et CR); si une telle ligne correspond, ne conservez que ce qu'il y a entre les crochets ( \ 1 , ce qui correspond à ce qu'il y a entre \ (... \) dans l'expression régulière) avant l'impression ( : p )
    • sed affichera des lignes ressemblant à: 8541, 931, 0, 0
  • awk utilise une virgule entourée d'au moins 0 espaces ( -F '*, *' ) comme délimiteurs de champs; $ 1 correspond à la première colonne (par exemple 8541), $ 2 à la seconde etc. Les colonnes manquantes comptent comme valeur 0
    • à la fin, awk divise les accumulateurs sum2 etc. en nombre d'enregistrements traités, NR
  • gawk fait tout d'un coup; il testera d'abord si chaque ligne correspond à la même expression régulière transmise dans l'exemple précédent à sed (sauf que contrairement à sed , awk ne nécessite pas \ entre les parenthèses délimitant des zones ou des intérêts). Si la ligne est la même, ce qui est entre les crochets arrondis se termine par un [1], que nous séparons ensuite à l'aide du même séparateur (une virgule entourée d'un nombre quelconque d'espaces) et que nous utilisons pour l'accumuler. J'ai introduit cnt au lieu de continuer à utiliser NR car le nombre d'enregistrements traités NR peut être supérieur au nombre réel d'enregistrements pertinents ( cnt ) si toutes les lignes ne sont pas de la forme INFO ... [... nombres-séparés par des virgules ...] , ce qui n'était pas le cas avec sed | awk puisque sed garantit que toutes les lignes transmises à awk sont pertinentes.

Utilisez nawk ou / usr / xpg4 / bin / awk sur Solaris .

awk -F'[],]' 'END { 
  print s/NR, t/ct 
  }  
{ 
  s += $(NF-3) 
  if ($(NF-1)) {
    t += $(NF-2)
    ct++
    }
  }' infile

Utiliser Python

logfile= open( "somelogfile.log", "r" )
sum2, count2= 0, 0
sum3, count3= 0, 0
for line in logfile:
    # find right-most brackets
    _, bracket, fieldtext = line.rpartition('[')
    datatext, bracket, _ = fieldtext.partition(']')
    # split fields and convert to integers
    data = map( int, datatext.split(',') )
    # compute sums and counts
    sum2 += data[1]
    count2 += 1
    if data[3] != 0:
        sum3 += data[2]
        count3 += 1
logfile.close()

print sum2, count2, float(sum2)/count2
print sum3, count3, float(sum3)/count3
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top